Home > Back-end >  Merging array of objects by different ids
Merging array of objects by different ids

Time:06-25

I have such a case:

const ids = {
// id: parentId
  "2": "1",
  "3": "1"
}

const input = [
  {
    id: "1",
    data: [1],
  },
   {
     id: "2",
     data: [2]
   },
   {
     id: "3",
     data: [3]
   },
   {
     id: "4",
     data: [4]
   }
]

const output = [
  {
    id: "1",
    data: [1,2,3]
  },
  {
    id: "4",
    data: [4]
  }
]

With this ids I wanted to create some kind of config, which will determine which object in input array should have merged data (if there is no id-parentId pair defined, it should stay as it is). I belive code above is better explanation than this story. I tried with some mappings but without any nice result. This 'ids' array is an example, maybe there is a better way to define it so it will simplify the case? What do you think? I will be grateful for any hint

CodePudding user response:

You can use reduce(). Create the output first as an object that uses id as the key. You can convert it to an array at the end with Object.values().

const ids = {
  // id: parentId
  "2": "1",
  "3": "1"
}

const input = [{
    id: "1",
    data: [1],
  },
  {
    id: "2",
    data: [2]
  },
  {
    id: "3",
    data: [3]
  },
  {
    id: "4",
    data: [4]
  }
]

const output = Object.values(input.reduce((acc, {
  id,
  data
}) => {
  if (id in ids) { // replace id with parent
    id = ids[id];
  }
  if (id in acc) {
    acc[id].data = acc[id].data.concat(data);
  } else {
    acc[id] = {
      id,
      data};
  }
  return acc;
}, {}));

console.log(output);

CodePudding user response:

You could take the references for same groups.

const
    ids = { 2: "1", 3: "1" },
    input = [{ id: "1", data: [1] }, { id: "2", data: [2] }, { id: "3", data: [3] }, { id: "4", data: [4] }],
    output = Object.values(input.reduce((r, { id, data }) => {
        id = ids[id] ?? id;
        (r[id] ??= { id, data: [] }).data.push(...data);
        return r;
    }, {}));

console.log(output);
.as-console-wrapper { max-height: 100% !important; top: 0; }

CodePudding user response:

You can try to cycle the input and modifying it in place, something like this should work:

const input = [
  {
    id: '1',
    data: [1]
  },
  {
    id: '2',
    data: [2]
  },
  {
    id: '3',
    data: [3]
  },
  {
    id: '4',
    data: [4]
  }
]

const config = {
  2: '1',
  3: '1'
}

const merge = ({ input, config } = {}) => {
  for (const [childId, parentId] of Object.entries(config)) {
    const childIndex = input.findIndex(i => i.id == childId)
    const parent = input.find(i => i.id == parentId)
    parent.data.push(...input[childIndex].data)
    input.splice(childIndex, 1)
  }

  return input
}

console.log(merge({ input, config }))

CodePudding user response:

you could do it like this:

let ids = { 2: "1", 3: "1" }
let input = [{ id: "1", data: [1] }, { id: "2", data: [2] }, { id: "3", data: [3] }, { id: "4", data: [4] }];
let keys = Object.keys(ids);
let objs = input.slice();//in order to not mutate the source input
const output = objs.map(currObj=>{
    let currId = currObj.id;
    if(keys.includes(currId)){
        let changeObj = objs.find(obj=>obj.id==ids[currId])
        changeObj.data.push(...currObj.data)
    }
    return currObj
})
console.log(output);

NOTE: I used slice() in order to not mutate the source input

CodePudding user response:

You can use Array#reduce, Object.entries and Array#map methods as follows:

const ids = { "2": "1", "3": "1" },
      input = [ { id: "1", data: [1], }, { id: "2", data: [2] }, { id: "3", data: [3] }, { id: "4", data: [4] } ],

output = Object.entries(
    input.reduce(
        (acc,{id,data}) =>
        ids[id] ?
        ({...acc,[ids[id]]:[...(acc[ids[id]] || []),...data]}) :
        ({...acc,[id]:[...(acc[id] || []), ...data]}),{}
    )
)
.map(([id,data]) => ({id,data}));

console.log( output );
//OUTPUT: [{"id":"1","data":[1,2,3]},{"id":"4","data":[4]}]

  • Related