I am trying to flatten the below data structure, I feel like there must be a good way fo doing this without manually iterating through each element to manually build it.
[{
group: 'abc',
data: [{
name: 'John',
age: 10
}, {
name: 'Alice',
age: 15
}]
}, {
group: 'def',
data: [{
name: 'Scott',
age: 20
}, {
name: 'Tamar',
age: 25
}]
}]
and I wanted it to be something like this instead (so the group is alongside the data):
[{
group: 'abc',
name: 'John',
age: 10
}, {
group: 'abc',
name: 'Alice',
age: 15
}, {
group: 'def',
name: 'Scott',
age: 20
}, {
group: 'def',
name: 'Tamar',
age: 25
}]
Any ideas would be appreciated.
const a = [
{group: 'abc', data: [{name: 'John', age: 10}, {name: 'Alice', age: 15}]},
{group: 'def', data: [{name: 'Scott', age: 20}, {name: 'Tamar', age: 25}]}
];
const flat = a.flatMap(({group, data}) => data.map(o => Object.assign({group}, o)));
console.log(flat)
// Unmodified original Array:
console.log(a)
MDN Array.prototype.flatMap()
MDN Array.prototype.map()
MDN Object.assign()
Array#reduce would be helpful.
const a = [{group:'abc',data:[{name:'John',age:10},{name:'Alice',age:15}]},{group:'def',data:[{name:'Scott',age:20},{name:'Tamar',age:25}]}];
const r = a.reduce((s, { group, data }) =>
(data.forEach((o) => s.push({ ...o, group })), s), []);
console.log(r);
Iterate the array with Array.flatMap(), then map each group, and construct the new objects using object spread:
const arr = [{"group":"abc","data":[{"name":"John","age":10},{"name":"Alice","age":15}]},{"group":"def","data":[{"name":"Scott","age":20},{"name":"Tamar","age":25}]}]
const result = arr.flatMap(({ group, data }) => data.map(o => ({ group, ...o })))
console.log(result)
Related
People is my model, data is my new information, and the forEach is how I am trying to insert the new data into my model, but formatted to only the information I care about
people = [{name: '', age: 0}];
data = [
{id: '123', name: 'Bob', lastName: 'Guy', age: 40},
{id: '321', name: 'Michael', lastName: 'Park', age: 20},
]
data.forEach(person => {
people.push({
name: person.name,
age: person.age,
});
});
However, the result I get is this:
people = [
{name: '', age: 0},
{name: 'Bob', age: 40},
{name: 'Michael', age: 20}
];
I'm trying to have the object array look like this instead:
people = [
{name: 'Bob', age: 40},
{name: 'Michael', age: 20}
];
However, I would like to know if theres a way to do it without an extra line of code (like popping the first element), and if theres a way to do it in one command? If not, I am open to suggestions. Thank you!
You're using the original array and not only that but also you're mutating the array.
You can use the function Array.prototype.map in order to generate a new array with the desired data.
const people = [{name: '', age: 0}];
const data = [
{id: '123', name: 'Bob', lastName: 'Guy', age: 40},
{id: '321', name: 'Michael', lastName: 'Park', age: 20},
]
const result = data.map(person => ({
name: person.name,
age: person.age,
}));
console.log(result);
You can also keep the desired keys and by using the functions Array.prototype.map and Array.prototype.reduce you can build the expected result:
const model = ["name", "age"];
const data = [
{id: '123', name: 'Bob', lastName: 'Guy', age: 40},
{id: '321', name: 'Michael', lastName: 'Park', age: 20},
]
const result = data.map(person => model.reduce((r, m) => ({...r, [m]: person[m]}), {}), []);
console.log(result);
Just in case you need to implement different person models, you can dinamically create the objects like this
peopleModel = [{ name: "", age: 0 }];
data = [
{ id: "123", name: "Bob", lastName: "Guy", age: 40 },
{ id: "321", name: "Michael", lastName: "Park", age: 20 },
];
const keysArr = Object.keys(peopleModel[0]);
const totalKeys = keysArr.length;
const people = data.reduce((acc, personObj) => {
const obj = {};
keysArr.forEach((key) => {
if (personObj[key]) {
obj[key] = personObj[key];
}
});
acc.push(obj);
return acc;
}, []);
console.log(people);
/* logs [
{name: 'Bob', age: 40},
{name: 'Michael', age: 20}
];
*/
but if you need a different model like
peopleModel = [{ name: "", age: 0, lastName: "" }]
you will get for the log the following:
[
{name: 'Bob', age: 40, lastName: 'Guy'},
{name: 'Michael', age: 20, lastName: 'Park'}
];
that way you do not need to hardcode the keys
Consider the following two arrays:
[
{
id: jhz,
name: 'John',
eyes: 'Green',
description: 'Cool guy',
},
{
id: mbe,
name: 'Mary',
brand: 'M&B',
text: 'Something',
}
]
[
{
id: jhz,
name: 'John',
eyes: '',
},
{
id: mbe,
name: 'Mary',
},
{
id: 'beh',
name: 'Bernard',
}
]
First array may have any kind of key value pairs, but it will always have the key id and name. I want to merge the two arrays by taking id and name into account and preserving them, while merging everything else and replacing them with data from the first array if any keys duplicate.
Also tricky part - the merged array needs to follow the order of the second array.
So in this example the result I'm looking for is:
[
{
id: jhz,
name: 'John',
eyes: 'Green',
description: 'Cool guy',
},
{
id: mbe,
name: 'Mary',
brand: 'M&B',
text: 'Something',
},
{
id: 'beh',
name: 'Bernard',
}
]
you can do something like this using Array.map
const data1 = [{
id: 'jhz',
name: 'John',
eyes: 'Green',
description: 'Cool guy',
},
{
id: 'mbe',
name: 'Mary',
brand: 'M&B',
text: 'Something',
}
]
const data2 = [{
id: 'jhz',
name: 'John',
eyes: '',
},
{
id: 'mbe',
name: 'Mary',
},
{
id: 'beh',
name: 'Bernard',
}
]
const result = data2.map(d => ({...d, ...(data1.find(d1 => d1.id === d.id && d1.name === d.name) || {})}))
console.log(result)
I am trying to compare 2 objects by their property and the values Strictly using forloop. If the value of the "name" or another property matches up with each other, I want to push the property and value to value3.
Once value3 is logged, I want the response like this:
{
name: 'dog',
surname: 'good',
skills: 'programming',
age: '22'
},
{
name: 'cat',
surname: 'soft',
skills: 'engineer'
age: '12'
},
{
name: 'elephant',
surname: 'big',
skills: 'programming'
age: '23'
}
Here is the code:
var values1 = [
{
name: 'dog',
surname: 'good',
skills: 'programming'
},
{
name: 'cat',
surname: 'soft',
skills: 'engineer'
},
{
name: 'elephant',
surname: 'big',
skills: 'programming'
}
]
var values2 = [
{
name: 'cat',
food: 'fish',
age: '12'
},
{
name: 'elephant',
food: 'leafs',
age: '13'
},
{
lastname: 'dog',
food: 'treats',
age: '22'
}
]
// push into this empty object array
var values3 = [{}]
console.log(values3)
The most generic approach which fulfills all of the OP's requirements should be based on Array.prototype.reduce. Its advantage comes with utilizing the additionally passed optional initial value as kind of configurable collector/accumulator object which will carry all the needed additional information / functions / result. Thus one can provide a reusable function with a customizable context/environment which one can adapt to ones needs.
var values1 = [{
name: 'dog',
surname: 'good',
skills: 'programming',
}, {
name: 'cat',
surname: 'soft',
skills: 'engineer',
}, {
name: 'elephant',
surname: 'big',
skills: 'programming',
}];
var values2 = [{
name: 'cat',
food: 'fish',
age: '12'
}, {
name: 'elephant',
food: 'leafs',
age: '13'
}, {
lastname: 'dog',
food: 'treats',
age: '22'
}];
function mergeItemsOfSameEntry(collector, item) {
const {
getSameEntryValue,
getMergeSubType,
comparisonItems,
result
} = collector;
const itemValue = getSameEntryValue(item);
const comparisonItem = comparisonItems
.find(cItem => getSameEntryValue(cItem) === itemValue);
if (comparisonItem !== null) {
result.push({
...item,
...getMergeSubType(comparisonItem),
});
}
return collector;
}
const values3 = values1.reduce(mergeItemsOfSameEntry, {
getSameEntryValue: item => item.name ?? item.lastname,
getMergeSubType: ({ age }) => ({ age }),
comparisonItems: values2,
result: [],
}).result;
console.log({ values3 });
.as-console-wrapper { min-height: 100%!important; top: 0; }
If you just want the key and value pair, you can do something like this:
var values1 = [
{
name: 'dog',
surname: 'good',
skills: 'programming'
},
{
name: 'cat',
surname: 'soft',
skills: 'engineer'
},
{
name: 'elephant',
surname: 'big',
skills: 'programming'
}
]
var values2 = [
{
name: 'cat',
food: 'fish',
age: '12'
},
{
name: 'elephant',
food: 'leafs',
age: '13'
},
{
lastname: 'dog',
food: 'treats',
age: '22'
}
]
// push into this empty object array
var values3 = [];
values1.forEach(eachValue1Obj => {
const keys = Object.keys(eachValue1Obj);
keys.forEach(eachKey => {
values2.forEach(eachValue2Obj => {
if (
eachValue1Obj[eachKey] &&
eachValue2Obj[eachKey] &&
eachValue1Obj[eachKey] === eachValue2Obj[eachKey]
) {
const x = {
key: eachKey,
value: eachValue1Obj[eachKey]
};
values3.push(x)
}
})
})
})
console.log('Values 3 Array ==>', values3);
I have a data with structure like this:
const arr1 = [
{
name: 'a',
subObjects: [
{ name: 'a1', age: 10 },
{ name: 'a2', age: 12 },
],
},
{ name: 'b', age: 23 },
{
name: 'c',
subObjects: [
{ name: 'c1', age: 30 },
{ name: 'c2', age: 32 },
],
},
...
];
So, the array contains an array of objects, some objects also contain nested level object subObjects which contains the same structure as parent. Overall some 1st level object in array can have maximum two levels of nest (like above example shows).
Now, I need to have an array that gather all names of objects from above array, something like:
[
{ name: 'a' },
{ name: 'a1' },
{ name: 'a2' },
{ name: 'b' },
{ name: 'c' },
{ name: 'c1' },
{ name: 'c2' },
];
This is what I tried:
const arr1 = [
{
name: 'a',
subObjects: [
{ name: 'a1', age: 10 },
{ name: 'a2', age: 12 },
],
},
{ name: 'b', age: 23 },
{
name: 'c',
subObjects: [
{ name: 'c1', age: 30 },
{ name: 'c2', age: 32 },
],
},
];
const arr2 = arr1.map((obj) => {
return obj.subObjects ? obj.subObjects.flat() : obj.name;
});
console.log(arr2.flat());
But the output lost the 1st level object names for those who has nested objects. So, what is the best way to achieve what I need?
You could use a recursive flatMap to do it (with a little help from the spread oparator!):
const arr1 = [{name: 'a', subObjects:[{name: 'a1', age: 10}, {name: 'a2', age: 12},]}, {name: 'b', age: 23}, {name: 'c', subObjects:[{name: 'c1', age: 30}, {name: 'c2', age: 32},]}];
const recursiveFlat = (arr) => arr.flatMap(
a => a.subObjects
? [{name: a.name}, ...recursiveFlat(a.subObjects)]
: {name: a.name});
console.log(recursiveFlat(arr1));
This will work with any depth of nesting.
I have an array of object arrayOfUsers as below and i want to filter that dynamically based on the object filterValues. If i remove name from filterValues the code should filter the array with age only and if i add id also to filterValues it should filter the array with three properties with out directly specifying key in the filter code and the key should capture from filterValues. I would like to get a solution for this using callback function. Appreciate for the solutions.
const arrayOfUsers = [
{ id: 1, name: 'Sam', age: 33 },
{ id: 2, name: 'Ram', age: 34 },
{ id: 3, name: 'Raj', age: 32 },
{ id: 4, name: 'Som', age: 2 }]
const filterValues = { name: 'R', age: 3 }
Expected Output:
[
{ id: 2, name: 'Ram', age: 34 },
{ id: 3, name: 'Raj', age: 32 }
]
Here is the sample code where i am stuck on.
const test = (arr) => {
Object.keys(filterValues).map((key, i) => arr.filter((user) => user[key].includes(key[i])))
}
You could convert the properties to string and seach for a substring.
const
arrayOfUsers = [{ id: 1, name: 'Sam', age: 33 }, { id: 2, name: 'Ram', age: 34 }, { id: 3, name: 'Raj', age: 32 }, { id: 4, name: 'Som', age: 2 }],
filterValues = { name: 'R', age: 3 },
filters = Object.entries(filterValues),
result = arrayOfUsers.filter(user => filters.every(([key, value]) =>
user[key].toString().includes(value)
));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }