10

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?

2
  • 3
    is every object in arrayOfObjects guaranteed to have the same properties? Commented Oct 11, 2018 at 13:26
  • @Rafonix You should accept the best answer. Commented Oct 12, 2018 at 7:56

12 Answers 12

9

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);

Sign up to request clarification or add additional context in comments.

Comments

7

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);

Comments

7

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()

4 Comments

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'}
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.
@Akrion: yep, I see, fixed!
@georg isn't the fixed lodash version exactly look like my answer?
4

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>

Comments

4

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);

Comments

4

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.

2 Comments

You can't use for..of on an object, you should use for..in instead, or iterate over Object.keys(result).
@Frax Oops, that's what I meant.
2

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

2 Comments

This results in a slightly different output structure than expected.
@ssc-hrep3 see edit, I forget to map it to the expected type of result
2

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)

Comments

1

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);

Comments

0

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;
}, {});

Comments

0

Without any library

const mergeObjectInArray=(input)=>{
const myObj={};
Object.keys(input[0]).forEach(key=>myObj[key]=input.map(inp=>inp[key]));
return myObj;
}

Comments

0

with pure javascript

var myInput = [{ a: 1, b: 2, c: 3 }, { a: 2, b: 4, c: 6 }, { a: 7, b: 8, c: 9 }];
    var myArray = [];
    var myObject = {};
    function isArray(a){
        return Object.prototype.toString.call(a) === '[object Array]' ;
    }
    for (var i = 0; i < myInput.length; i++) {
        for (var key in myInput[i]) {
            if (myInput[i].hasOwnProperty(key)) {
                if (myArray.indexOf(key) === -1) {
                    myArray.push(key);
                    myObject[key] = myInput[i][key];
                } else {
                    if (myObject.hasOwnProperty(key)) {
                        newary = [];
                        if (isArray(myObject[key])) {
                            for (var i = 0; i < myObject[key].length; i++) {
                                newary.push(myObject[key][i]);
                            }
                        } else {
                            newary.push(myObject[key]);
                        }
                        newary.push(myInput[i][key]);
                        myObject[key] = newary;
                    }
                }
            }
        }
    }
    console.log(myObject);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.