How can you merge objects in array of objects?

2020-02-07 00:25发布

问题:

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?

回答1:

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>



回答2:

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



回答3:

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



回答4:

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


回答5:

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



回答6:

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.



回答7:

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



回答8:

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)



回答9:

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


回答10:

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


回答11:

Without any library

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


回答12:

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