yury_hr
yury_hr

Reputation: 33

What is the best way to merge nested arrays

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

Answers (3)

Karambit
Karambit

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

Himanshu
Himanshu

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

trincot
trincot

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

Related Questions