By Rafonix


2018-10-11 13:24:54 8 Comments

I'm looking for the best solution to merge all objects in one array

const arrayOfObjects = [
 {name: 'Fred', surname: 'Shultz'}, {name: 'Anne', surname: 'Example'}
];

I want to achieve: {name: ['Fred', 'Anne'], surname: ['Example', 'Shultz']}

What's the best option for that (es6)? Maybe I can do something like that using lodash? Which helpers should I use?

10 comments

@Jimi Pajala 2018-10-27 14:31:55

This is one abroach of implementation details, written in fairly easy to understand and readable manner.

https://codesandbox.io/s/r7x16j950n

const arrayOfObjects = [
  { name: "Fred", surname: "Shultz" },
  { name: "Anne", surname: "Example" }
];

let obj = {};

arrayOfObjects.forEach(row => {
  Object.keys(row).forEach(key => {
    obj[key] = !obj[key]
      ? [row[key]]
      : [...obj[key], row[key]];
  });
});

console.log(obj);

@Bergi 2018-10-11 19:34:57

Don't make it any more complicated than it needs to be:

const arrayOfObjects = [
    {name: 'Fred', surname: 'Shultz'},
    {name: 'Anne', surname: 'Example'}
];

const result = {name:[], surname:[]};
for (const obj of arrayOfObjects)
    for (const prop in result)
        result[prop].push(obj[prop]);

I will assume that you statically know the property names that your result should have - one can't really do it dynamically anyway as that wouldn't work properly for an empty input array.

@Frax 2018-10-12 00:30:04

You can't use for..of on an object, you should use for..in instead, or iterate over Object.keys(result).

@Bergi 2018-10-12 10:01:14

@Frax Oops, that's what I meant.

@georg 2018-10-11 13:30:51

easy with lodash:

grouped = _.mapValues(arrayOfObjects[0], 
    (val, key) => _.map(arrayOfObjects, key))

pure es6

let grouped = {};

for (let obj of arrayOfObjects)
    for (let [key, val] of Object.entries(obj))
        grouped[key] = (grouped[key] || []).concat(val)

if the keys differ from item to item, you could use something like this to collect them all:

grouped = _(arrayOfObjects)
    .flatMap(_.entries)
    .groupBy(0)
    .mapValues(x => _.map(x, 1))
    .value()

@Akrion 2018-10-11 18:51:23

I liked the lodash approach but it is not generic enough. It will break if any objects past the first one have different properties. e.g. {name: 'John', city: 'Miami'}

@Akrion 2018-10-11 22:54:24

Look at jsfiddle.net/akrion/tp70frm5/627. You will see in the console that first you have an undefined as last element in the surname and 2nd you have no property for city since you did mapValues on the first object and not on every in the array.

@georg 2018-10-11 23:05:07

@Akrion: yep, I see, fixed!

@Koushik Chatterjee 2018-10-13 16:49:47

@georg isn't the fixed lodash version exactly look like my answer?

@Akrion 2018-10-11 16:55:26

If the arrayOfObjects is set on these 2 props then it is as simple as:

const data = [{ name: 'Fred', surname: 'Shultz' }, { name: 'Anne', surname: 'Example' }]

const r = data.reduce((r,c) => 
   (r.name.push(c.name), r.surname.push(c.surname),r), {name:[], surname:[]})

console.log(r)

One reduce with an accumulator of {name:[], surname:[]} to be filled.

If you need to be more generic and work for any set of objects:

const data = [{
  name: 'Fred',
  surname: 'Shultz'
},{
  name: 'Anne',
  surname: 'Example'	
},{
  name: 'John',
  position: 'Dev' // <--- Notice different prop
}]

const result = data.reduce((r,c) => 
  (Object.keys(c).map(k => r[k] = [...r[k] || [], c[k]]), r), {})

console.log(result)

Again is just a reduce with Object.keys to do the job.

Note both approaches utilize ES6 arrow functions, array destricturing and (for the 2nd one) combining multiple operations via enclosing them in parentheses (op1,op2)

@protoproto 2018-10-11 14:06:22

Short way with array reduce:

const arrayOfObjects = [
 {name: "name1", surname: "surname1"}, {name: 'Anne', surname: 'Example'}, {name: 'name3', surname: 'Example3'}
];
/*
{name: ['Fred', 'Anne'], surname: ['Example', 'Shultz']}
*/
var result = arrayOfObjects.reduce((obj,current)=>{
    (obj['name'] = obj['name']||[]).push(current.name);
    (obj['surname'] = obj['surname']||[]).push(current.surname);
    return obj;
},{});
console.log(result);

@ibrahim mahrir 2018-10-11 13:57:19

You can use lodash's mergeWith like so:

const result = _.mergeWith({}, ...arrayOfObjects, (value, objValue) =>
    (value || []).concat(objValue)
);

Example:

const arrayOfObjects = [
    {name: 'Fred', surname: 'Shultz'}, {name: 'Anne', surname: 'Example'}
];

const result = _.mergeWith({}, ...arrayOfObjects, (value, objValue) =>
    (value || []).concat(objValue)
);

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

@Koushik Chatterjee 2018-10-11 13:38:42

Here is a lodash approach

  _(input).flatMap(_.entries).groupBy(0).mapValues(v => _.map(v, 1)).value()

var input = [
 {name: 'Fred', surname: 'Shultz'}, {name: 'Anne', surname: 'Example'}
];

var res =   _(input).flatMap(_.entries).groupBy(0).mapValues(v => _.map(v, 1)).value()

console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

This will take care if the objects doesn't have exactly same key sets

@ssc-hrep3 2018-10-11 13:40:06

This results in a slightly different output structure than expected.

@Koushik Chatterjee 2018-10-11 13:41:27

Ohh, yeah, need to map the value, let me edit

@Koushik Chatterjee 2018-10-11 13:54:16

@ssc-hrep3 see edit, I forget to map it to the expected type of result

@Nina Scholz 2018-10-11 13:37:15

You could reduce the array by iterating the entries and collecting the values, depending of the keys.

const
    array = [{ name: 'Fred', surname: 'Shultz' }, { name: 'Anne', surname: 'Example' }],
    result = array.reduce((r, o) => {
        Object.entries(o).forEach(([k, v]) => (r[k] = r[k] || []).push(v));
        return r;
    }, Object.create(null));

console.log(result);

@ssc-hrep3 2018-10-11 13:34:13

You could do it like this:

const arrayOfObjects = [
  {name: 'Fred', surname: 'Shultz'}, {name: 'Anne', surname: 'Example'}
];

const result = {};
arrayOfObjects.forEach(item => {
  Object.keys(item).forEach(key => {
    if (!result[key]) {
      result[key] = [];
    }
    result[key].push(item[key]);
  });
});

console.log(result);

@Robin Zigmond 2018-10-11 13:30:29

The following should work - uses a few ES6 helpers, but the key is Array#reduce which is in ES5.

const result = arrayOfObjects.reduce((acc, obj) => {
    for (let key in obj) {
        if (key in acc) {
            acc[key].push(obj[key]);
        }
        else {
            acc[key] = [obj[key]];
        }
    }
    return acc;
}, {});

Related Questions

Sponsored Content

33 Answered Questions

[SOLVED] How do I return the response from an asynchronous call?

43 Answered Questions

41 Answered Questions

[SOLVED] Check if object is an array?

37 Answered Questions

[SOLVED] How do I remove a property from a JavaScript object?

69 Answered Questions

[SOLVED] How do I remove a particular element from an array in JavaScript?

  • 2011-04-23 22:17:18
  • Walker
  • 5294524 View
  • 6590 Score
  • 69 Answer
  • Tags:   javascript arrays

86 Answered Questions

[SOLVED] How do JavaScript closures work?

30 Answered Questions

[SOLVED] How to append something to an array?

28 Answered Questions

[SOLVED] For-each over an array in JavaScript?

33 Answered Questions

58 Answered Questions

[SOLVED] How do I redirect to another webpage?

Sponsored Content