Related
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.
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.
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 }
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/
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
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))
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 :)
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.
With more modern spread operator
arrOfObj.reduce( (acc, curr) => ({ ...acc, ...cur }) );
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);
}, []);
};
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];
})
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));
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.
I have a two dimension array like this
[
[{ a: 1 }, { a: 2 }, { a: 3 }],
[{ b: 1 }, { b: 2 }, { b: 3 }],
[{ c: 1 }, { c: 2 }, { c: 3 }]
]
Is there any way to merge it as
[
[{ a: 1, b: 1, c: 1 }],
[{ a: 2, b: 2, c: 2 }],
[{ a: 3, b: 3, c: 3 }]
]
All proposed approaches until now use a combination of Array.prototype.map and Array.prototype.reduce. In addition every approach for creating the merged objects uses either Object.assign or the spread syntax for/within object literals or both.
These are just tools. But one needs to have a basic understanding of the available tools and how they work in order to come up with an algorithm.
One, of cause could solve the problem via for/while based loops but it would not contribute to readability.
Thus, dear OP, read yourself not just through the documentation of e.g. Array and Object; but maybe start from there.
function zipAndMergeWithBoundArray(obj, idx) {
return this.reduce(
(assignee, vector) => Object.assign(assignee, vector[idx]),
{ ...obj } // shallow copy in order to not mutate the original
);
}
const sampleArray = [
[{ a: 1 }, { a: 2 }, { a: 3 }], // take the first row/vector ...
[{ b: 1 }, { b: 2 }, { b: 3 }], // ... and zip&merge it
[{ c: 1 }, { c: 2 }, { c: 3 }], // ... with the other
[{ d: 1 }, { d: 2 }, { d: 3 }], // ... rows/vectors
[{ e: 1 }, { e: 2 }, { e: 3 }] // ... of the table/matrix rest.
];
console.log(
//first vector // table/matrix rest
sampleArray[0].map(zipAndMergeWithBoundArray, sampleArray.slice(1))
);
// remains not mutated...
console.log(sampleArray);
.as-console-wrapper { min-height: 100%!important; top: 0; }
You could do 2 steps: first transpose the array, then merge each element
const input = [
[{ a: 1 }, { a: 2 }, { a: 3 }],
[{ b: 1 }, { b: 2 }, { b: 3 }],
[{ c: 1 }, { c: 2 }, { c: 3 }]
]
const transpose = array =>
array[0].map((a, i) => array.map(b => b[i]))
const mergeAll = arrOfObj =>
arrOfObj.reduce((acc, el) => Object.assign(acc, el), {})
const res = transpose(input).map(mergeAll)
console.log(res)
You could reduce the outer array and map the inner array with the objects at the same index of the result array.
const
data = [[{ a: 1 }, { a: 2 }, { a: 3 }], [{ b: 1 }, { b: 2 }, { b: 3 }], [{ c: 1 }, { c: 2 }, { c: 3 }]],
result = data.reduce(
(target, objects) => objects.map((object, index) => ({ ...target[index], ...object })),
[]
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I have nested objects within an object as such:
var parentObj = {
key1: {
a: true,
b: 2
},
key2: {
a: false,
b: 2
},
key3: {
a: true,
b: 2
}
}
I'm looking to create an array of objects from key values, if one of the values in the nested objects is true, and that also includes the keys as a [key,value] pair as such:
parentobj = [
{
a: true,
b: 2,
c: "key1"
},
{
a: true,
b: 2,
c: "key3"
}
]
Just use a for...in loop, like so:
var myArray = [];
for(var key in parentObj){
var childObj = parentObj[key];
if(childObj.a) {
myArray.push({a: childObj.a, b: childObj.b, c: key });
}
}
First thing to mention here is
Associative arrays do not exist in Javascript
you can see here
In your example "key1" is duplicated so if you want to store like then then you have to use Array for that like if one of the values in the nested objects is true
var parentObj = {
key1: [
{
a: true,
b: 2
},
{
a: false,
b: 2
}
],
key3: [
{
a: true,
b: 2
}
]
};
In that case what you want is done like this !
var parentObj = {
key1: [
{
a: true,
b: 2
},
{
a: false,
b: 2
}
],
key3: [
{
a: true,
b: 2
}
]
};
var myArray = [];
for(var key in parentObj){
var childObj = parentObj[key];
var res = childObj.filter(function(element){
return element.a == true;
});
for(ele in res){
res[ele].c = key;
}
if(res.length > 0){
// if you want any of element having true property
myArray.push(res[0]);
}
}
console.log(myArray);
A simple one-line solution: extract keys from the object and iterate over them while creating respective objects and filter out the falsy ones:
var parentObj = {
key1: {
a: true,
b: 2
},
key2: {
a: false,
b: 2
},
key3: {
a: true,
b: 2
}
};
var result = Object.keys(parentObj).map(k => (Object.assign({}, parentObj[k], {c: k}))).filter(({a}) => a);
console.log(result);
How do I use Object.assign to update the second object in the allMsgs array?
I have:
let v = {
allMsgs: [
{
a: 111,
b: [],
},
{
a: 222,
b: [],
}
]
}
I want to have a copy of v so that it is:
let v = {
allMsgs: [
{
a: 111,
b: [],
},
{
a: 222,
b: ['newItem],
}
]
}
How do I use Object.assign for this?
Simply select the part which you want to update
let v = {
allMsgs: [
{
a: 111,
b: [],
},
{
a: 222,
b: [],
}
]
};
let vCopy = { allMsgs: v.allMsgs.map(msg => Object.assign({}, msg))};
vCopy.allMsgs[1] = Object.assign(vCopy.allMsgs[1], { b: ['newItem'] });
console.log('copy', vCopy);
console.log('actual', v);
Without Object.assign, you could address the array directly and push the value.
var v = { allMsgs: [{ a: 111, b: [] }, { a: 222, b: [] }] };
v.allMsgs[1].b.push('newItem');
console.log(v);
.as-console-wrapper { max-height: 100% !important; top: 0; }
If the goal is not to mutate the original object, then you would do it like this:
let v = {
allMsgs: [
{ a: 111, b: [] },
{ a: 222, b: [] }
]
};
let w = { allMsgs: Object.assign([...v.allMsgs],
{ 1: Object.assign({}, v.allMsgs[1],
{b: ['newItem']}
)}
)};
console.log('updated =', w);
console.log('original =', v);
Note that here the first object in allMsgs is still shared between the two objects. Only the one you wanted to change is (obviously) separate.
Libraries like immutable.js have nice methods for making such updates using a concise syntax.
i'm trying to work with reduce or map, but i'm a noob some times.
i'm trying to use this function to return a single array from the objects.
var obj = [{ a: 1 }, { b: 2 }, { c: 3 }];
var result = obj.reduce((obj, item) => [item.key] = item.value);
console.log(result);
but i'm always getting :
Uncaught TypeError: Cannot read property 'Symbol(Symbol.iterator)'
of undefined
I searched a lot, but the examples didn't help me... i think that's something simple, but after 1 hour, i'm nothing getting .
What i want..
[{a: 1}, {b: 2}, {c: 3}] to {a: 1, b: 2, c: 3}
You could use Object.assign and spread syntax ....
var obj = [{ a: 1 }, { b: 2 }, { c: 3 }];
console.log(Object.assign({}, ...obj));
With Array#reduce
var obj = [{ a: 1 }, { b: 2 }, { c: 3 }];
console.log(obj.reduce((r, o) => Object.assign(r, o), {}));
Without Object.assign
var obj = [{ a: 1 }, { b: 2 }, { c: 3 }];
console.log(obj.reduce((r, o) => (Object.entries(o).forEach(([k, v]) => r[k] = v), r), {}));
ES5
var obj = [{ a: 1 }, { b: 2 }, { c: 3 }];
console.log(obj.reduce(function (r, o) {
Object.keys(o).forEach(function (k) {
r[k] = o[k];
});
return r;
}, {}));
If you want to use reduce:
var arr = [{ a: 1 }, { b: 2 }, { c: 3 }];
var result = arr.reduce((obj, item) => Object.assign(obj, item), {});
Check the MDN documentation when in doubt.
you can do it in the following way using reduce
var obj = [{ a: 1 }, { b: 2 }, { c: 3 }];
var result = obj.reduce((obj, item) => {
Object.assign(obj, item)
return obj;
}, {});
console.log(result);