48

Given input:

[{ a: 1 }, { b: 2 }, { c: 3 }]

How to return:

{ a: 1, b: 2, c: 3 }

For arrays it's not a problem with lodash but here we have array of objects.

2
  • Is it even ok to ask on SO for npm packages? Commented Jun 30, 2015 at 10:59
  • No. You can describe the problem you're having, like you just did, and if the answer happens to be "install this npm package" then that's fine; but you shouldn't specifically ask for a package to solve the problem. Commented Jun 30, 2015 at 11:07

12 Answers 12

94

Use Object.assign:

let merged = Object.assign({}, ...arr); // ES6 (2015) syntax

var merged = Object.assign.apply(Object, arr); // ES5 syntax

Note that Object.assign is not yet implemented in many environment and you might need to polyfill it (either with core-js, another polyfill or using the polyfill on MDN).

You mentioned lodash, so it's worth pointing out it comes with a _.assign function for this purpose that does the same thing:

 var merged = _.assign.apply(_, [{ a: 1 }, { b: 2 }, { c: 3 }]);

But I really recommend the new standard library way.

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

6 Comments

Shouldn't you do Object.assign({}, ...arr)?!
@Bergi I can if I want to preserve the input of assign intact. I certainly don't have to if I don't. Since that was not a requirement I didn't treat it as such.
@BenjaminGruenbaum: Yes, preserving the input is a best practise :-) It can lead to ugly bugs when it's unexpected.
My linter throws a Expected at least 1 arguments, but got 0 or more. if I didn't add the extra {}; Object.assign({}, ...ids.
@jprio No, it works only on a single level. Object.assign is not recursive.
|
5

With lodash, you can use merge():

var arr = [ { a: 1 }, { b: 2 }, { c: 3 } ];
_.merge.apply(null, [{}].concat(arr));
// → { a: 1, b: 2, c: 3 }

If you're doing this in several places, you can make merge() a little more elegant by using partial() and spread():

var merge = _.spread(_.partial(_.merge, {}));
merge(arr);
// → { a: 1, b: 2, c: 3 }

Comments

4

Here is a version not using ES6 methods...

var arr = [{ a: 1 }, { b: 2 }, { c: 3 }];
var obj = {};

for(var i = 0; i < arr.length; i++) {
    var o = arr[i];
    for(var key in o) {
        if(typeof o[key] != 'function'){
            obj[key] = o[key];
        }
    }
}

console.log(obj);

fiddle: http://jsfiddle.net/yaw3wbb8/

5 Comments

Note that this will also copy enumerable prototype properties (which is not a problem in this particular case).
would a simple ` && !o.propertyIsEnumerable(key)` added to the if statement fix this?
Well, for... in only enumerates enumerable properties. A Object(o).hasOwnProperty(obj) would fix it though (ensuring it's not on the prototype) - the Object(o) part is to ensure we're not calling a non-existing method so that for example passing 4 would not fail (and copy nothing).
Aren't the enumerable properties the ones you would want to copy? For instance, you would not want something like Array.prototype.length in the object.. right? Or am I missing this entirely?
@BenjaminGruenbaum: Even better: Object.prototype.hasOwnProperty.call(o, i) to ensure we're not calling a custom method or even non-function property value.
4

You can use underscore.extend function like that:

var _ = require('underscore');
var a = [{ a: 1 }, { b: 2 }, { c: 3 }];

var result = _.extend.apply(null, a);
console.log(result); // { a: 1, b: 2, c: 3 }
console.log(a); // [ { a: 1, b: 2, c: 3 }, { b: 2 }, { c: 3 } ]

And to prevent modifying original array you should use

var _ = require('underscore');
var a = [{ a: 1 }, { b: 2 }, { c: 3 }];

var result = _.extend.apply(null, [{}].concat(a));
console.log(result); // { a: 1, b: 2, c: 3 }
console.log(a); // [ { a: 1 }, { b: 2 }, { c: 3 } ]

Here can test it

Comments

4

Adding to the accepted answer, a running code snippet with ES6.

let input = [{ a: 1 }, { b: 2 }, { c: 3 }]
//Get input object list with spread operator
console.log(...input)
//Get all elements in one object
console.log(Object.assign(...input))

1 Comment

This answer modifies the first object in input, which is fine in a simple example, but likely to lead to bugs in real code. The first argument should be {}, as discussed in the accepted answer.
1

I've got a neat little solution not requiring a polyfill.

var arr = [{ a: 1 }, { b: 2 }, { c: 3 }];
var object = {};

arr.map(function(obj){
    var prop = Object.getOwnPropertyNames(obj);
    object[prop] = obj[prop];
});

Hope that helps :)

6 Comments

I have no idea why this was upvoted since it can't doesn't work - getOwnPropertyNames returns an array.
This is just incidental since all the objects have a single property and toStringing the array with a single property gives the same result, try adding a property to one of the objects and see it failing: jsfiddle.net/zqvhceyj
@BenjaminGruenbaum I understand it perfectly - I was just applying a solution to the use case. I can be more generic, but the question clearly asked "for this input, return this output", I was merely doing so.
@JonathanBrooks and that's exacly what I've asked for. :-)
@Ultra Haha! That's what I gleaned from your question; I'm glad my downvotes are unwarranted :')
|
1

Here is a nice usage of Object.assign with the array.prototype.reduce function:

let merged = arrOfObjs.reduce((accum, val) => {
  Object.assign(accum, val);
  return accum;
}, {})

This approach does not mutate the input array of objects, which could help you avoid difficult to troubleshoot problems.

1 Comment

usefull when converting to another type of objects
0

You can easily flat your object to array.

function flatten(elements) {
  return elements.reduce((result, current) => {
    return result.concat(Array.isArray(current) ? flatten(current) : current);
  }, []);
};

Comments

0

6 years after this question was asked.

Object.assign is the answer (above) I like the most.

but is this also legal ?

let res = {};
[{ a: 1 }, { b: 2 }, { c: 3 }].forEach(val => {
    let key = Object.keys(val);
    console.log(key[0]);
    res[key] = val[key];
})

Comments

0

With more modern spread operator

arrOfObj.reduce( (acc, curr) => ({ ...acc, ...cur }) );

Comments

0
const data = [
  [{ a: "a" }, { b: "b" }, { c: "c" }],
  [{ d: "d" }, { e: "e" }, { f: "f" }],
  [{ g: "g" }, { h: "h" }, { i: "i" }],
];

function convertToObject(array){
  const response = {};
  for (let i = 0; i < array.length; i++) {
    const innerArray = array[i];
    for (let i = 0; i < innerArray.length; i++) {
      const object = innerArray[i];
      const keys = Object.keys(object);
      for (let j = 0; j < keys.length; j++) {
        const key = keys[j];
        response[key] = object[key];
      }
    }
  }
  return response;
}

console.log(convertToObject(data));

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
0

function carParts(manufacturer, model, ...parts) {
  return { manufacturer, model, ...Object.assign(...parts) };
}
console.log(
  carParts(
    "Honda",
    "2008",
    { color: "Halogen Lights" },
    { Gears: "Automatic Gears" },
    { LED: "Android LED" },
    { LED: "Android LED1" }
  )
);

This is how i have done.

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.