Reputation: 33
I have an array of objects that looks like this:
[
{external_id: 1, items: [{k: 'v'}] },
{external_id: 2, items: [{k1: 'v1'}] },
{external_id: 1, items: [{k2: 'v2'}, {k3: 'v3'}] }
]
What I want to do is merge nested arrays based on external_id
and return 'clean array' which will look like this:
[
{external_id: 1, items: [{k: 'v'}, {k2: 'v2'}, {k3: 'v3'}] },
{external_id: 2, items: [{k1: 'v1'}] }
]
So my question is what is the clean way to achieve that without using classic for-loop ?
Upvotes: 1
Views: 68
Reputation: 356
using another object to group objects with same external_id property
let a = [
{external_id: 1, items: [{k: 'v'}] },
{external_id: 2, items: [{k1: 'v1'}] },
{external_id: 1, items: [{k2: 'v2'}, {k3: 'v3'}] }
]
let obj = {};
a.forEach( ({external_id, items}) => {
obj[external_id] ??= new Set;
items.map( i => {
obj[external_id].add(JSON.stringify(i));
});
});
a = Object.keys(obj).map( (n) => {
n = Number(n);
return {
external_id:n,
items: [...obj[n]].map(JSON.parse)
}
})
Upvotes: 0
Reputation: 33
Using reduce and sort
let data = [{
external_id: 1,
items: [{
k: 'v'
}]
},
{
external_id: 2,
items: [{
k1: 'v1'
}]
},
{
external_id: 1,
items: [{
k2: 'v2'
}, {
k3: 'v3'
}]
},
];
let ans = data
.sort(function(a, b) {
return a['external_id'] - b['external_id'];
})
.reduce((acc, currentObject) => {
const endObject = acc[acc.length - 1];
if (endObject && endObject['external_id'] === currentObject.external_id) {
endObject.items.push(...currentObject.items);
} else {
acc.push({ ...currentObject
});
}
return acc;
}, []);
console.log(ans);
Upvotes: 1
Reputation: 350477
You will have to loop. You can choose to loop with for
, forEach
, map
, reduce
, find
, ...etc, but you'll have to loop.
Here is a way that creates a Map keyed by the external_id, and then populates that map with the items. Finally the values of that map represent the result:
let data = [{external_id: 1, items: [{k: 'v'}] },{external_id: 2, items: [{k1: 'v1'}] },{external_id: 1, items: [{k2: 'v2'}, {k3: 'v3'}] }];
let map = new Map(data.map(({external_id}) => [external_id, { external_id, items:[] }]));
data.forEach(o => map.get(o.external_id).items.push(...o.items));
let result = [...map.values()];
console.log(result);
Upvotes: 0