0

I am trying to combine an array of object into one object that merges the values of all of the like properties.

objArray = [{
  foo: ["f", "b"],
  bar: ["e"]
}, {
  foo: ["a", "c"],
  bar: ["a", "c"]
}, {
  foo: ["f", "b"],
  bar: ["z"]
}];
const newObj = {
  foo: [],
  bar: []
};
objArray.forEach((obj) => {
  newObj.foo.push(...obj.foo);
  newObj.bar.push(...obj.bar);
});
console.log(newObj);

I am getting the desired output with the above code. Is using a forEach loop like above the best way to achieve what I am setting out to do? Ideally I don't want to have to specify the properties to merge, I would like the code to merge identical property names automatically.

Edit:

I need to support IE11

Mcestone
  • 794
  • 3
  • 10
  • 26
  • 1
    Possible duplicate of [Merge multiple objects inside the same array into one object](https://stackoverflow.com/questions/27538349/merge-multiple-objects-inside-the-same-array-into-one-object) – Nisarg Sep 07 '18 at 14:13
  • 1
    Not a dupe @Nisarg – Feathercrown Sep 07 '18 at 14:15

5 Answers5

2

Can use a nested reduce() of Object#entries() to iterate properties without needing to hard code specific property names anywhere

objArray = [{
  foo: ["f", "b"],
  bar: ["e"]
}, {
  foo: ["a", "c"],
  bar: ["a", "c"]
}, {
  foo: ["f", "b"],
  bar: ["z"]
}];

const res= objArray.reduce((acc,c)=>{
   return Object.entries(c).reduce((a,[k,v])=>{
       a[k] = (a[k] || []).concat(v)
       return a
   },acc)
},{})

console.log(res)
charlietfl
  • 170,828
  • 13
  • 121
  • 150
  • Thank you, this is great. I'm realizing that I cannot use `Object.entries`. Are you able to add a solution without it? – Mcestone Sep 07 '18 at 15:20
  • Could add polyfill, it's not much code https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries#Polyfill – charlietfl Sep 07 '18 at 15:45
0

You could take the entries of the objects for an arbitrary count of keys and values.

var data = [{ foo: ["f", "b"], bar: ["e"] }, { foo: ["a", "c"], bar: ["a", "c"] }, { foo: ["f", "b"], bar: ["z"] }],
    merged = data.reduce((r, o) => 
        Object.entries(o).reduce((s, [k, v]) =>
            Object.assign(s, { [k]: (s[k] || []).concat(v) }), r), {});
        
console.log(merged);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
0

To achieve expected result, use Object.keys and two loops using forEach

  1. First loop with forEach will handle each object
  2. Second loop with Object.keys will handle each object keys and push to new Array with keys
  3. Use Object.hasOwnProperty to key value in newObj with original array object properties

objArray = [
  {
    foo: ["f", "b"],
    bar: ["e"],
    zoo: ["z"]
  },
  {
    foo: ["a", "c"],
    bar: ["a", "c"]
  },
  {
    foo: ["f", "b"],
    bar: ["z"]
  }
];
const newObj = {
  foo: [],
  bar: []
};
objArray.forEach(obj => {
  Object.keys(obj).forEach(v => {
    if (newObj.hasOwnProperty(v)) {
      newObj[v].push(obj[v]);
    }
  });
});
console.log(newObj);

codepen for reference - https://codepen.io/nagasai/pen/MqOpWm?editors=1010

Naga Sai A
  • 10,771
  • 1
  • 21
  • 40
0

Using forEach as you, but for in inside.

var objArray = [{foo: ["f", "b"],bar: ["e"]},{foo: ["a", "c"],bar:["a", "c"]},{foo: ["f", "b"],bar: ["z"]}];

var newObj = {};

objArray.forEach(o => {
  for (p in o) {
    if (!(p in newObj)) {
      newObj[p] = [];
    }
    newObj[p] = [...newObj[p], ...o[p]];
  }
});

console.log(newObj);
Emeeus
  • 5,072
  • 2
  • 25
  • 37
0

Taking @charlietfl answer and editing it for IE (using Object.keys instead of Object.entries)

objArray = [{
  foo: ["f", "b"],
  bar: ["e"]
}, {
  foo: ["a", "c"],
  bar: ["a", "c"]
}, {
  foo: ["f", "b"],
  bar: ["z"]
}];

const res = objArray.reduce((acc, c) => {
  return Object.keys(c).reduce((a, k) => {
    let v = c[k];
    a[k] = (a[k] || []).concat(v);
    return a;
  }, acc);
}, {});

console.log(res)
Mcestone
  • 794
  • 3
  • 10
  • 26