Convert array of array of objects into a single object [duplicate] - javascript

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.

Related

compare two array of objects keys, original array should mutate in javascript

How can we compare two array of objects on the basis of their keys or properties of object in javaScript?
for an example:
let result1 = [
{ a: 10, b: 20, c: 22 },
{ a: 20, b: 33, c: 11 },
];
let result2 = [
{ a: 10, b: 20 },
{ a: 20, b: 33 },
];
result1.filter(function (obj) {
return !result2.some(function (obj2) {
let key1 = Object.keys(obj);
let key2 = Object.keys(obj2);
key1?.forEach((x, index1) => {
key2?.forEach((y, index2) => {
console.log(index1, index2)
if (x === y) {
return obj[x] === obj2[y];
}
});
});
});
});
console.log(result1)
output: current output
expected output:
result1 =
[
{ a: 10, b: 20 },
{ a: 20, b: 33 },
];
I just try this solution in a different way, We can also achieve this requirement by doing deep copy of original array and then mutate it using forEach().
Live Demo :
let result1 = [
{ a: 10, b: 20, c: 22 },
{ a: 20, b: 33, c: 11 }
];
let result2 = [
{ a: 10, b: 20 },
{ a: 20, b: 33 }
];
const clone = structuredClone(result1);
clone.forEach((obj, index) => {
result1[index] = {};
Object.keys(result2[index]).forEach(key => {
result1[index][key] = obj[key]
});
});
console.log(result1);
let result1 = [
{ a: 10, b: 20, c: 22 },
{ a: 20, b: 33, c: 11 },
];
let result2 = [
{ a: 10, b: 20 },
{ a: 20, b: 33 },
];
let temp = []
result1.map(function(obj) {
return !result2.some(function(obj2) {
let key1 = Object.keys(obj);
let key2 = Object.keys(obj2);
key1.forEach((x) => {
key2.forEach((y) => {
if (x === y) {
obj[x] === obj2[y] ? temp.push({
[x]: obj[x]
}) : null;
}
})
});
})
})
console.log(temp);
try this code
You are getting the result1 array back beacause the array is not getting filtered.
The filter function is not getting anything from returned as the first foreach loop is not returning and the some function is also not returning anything
Now you can use map function instead of filter as the function is not returning anything
const filterKeysBasedOnFirstArrayOfObjects = <
T extends Record<string, unknown>
>(
arr1: T[],
arr2: T[]
) => {
const keys = _.intersection(
...arr1.map((obj) => Object.keys(obj)),
...arr2.map((obj) => Object.keys(obj))
);
return arr1.map((obj) => _.pick(obj, keys));
};
A more concise approach using lodash.

What is wrong in this sorting array skipping some elements?

I have array of objects. I want sort it leave some elements in the same position (with b="NOT")
var a=[{a:1,b:"YES"},{a:2,b:"YES"},{a:5,b:"NOT"},{a:0,b:"NOT"},{a:0,b:"YES"}]
function sortc(x,y){
if (x.b=="NOT" || y.b=="NOT")
return Infinity ;
return (Number(x.a)-Number(y.a))
}
console.log(a.sort(sortc));
the result is :
0: {a: 1, b: "YES"}
1: {a: 2, b: "YES"}
2: {a: 5, b: "NOT"}
3: {a: 0, b: "NOT"}
4: {a: 0, b: "YES"}
The expected result was ( with sort components with b="YES".) :
{ "a": 0, "b": "YES" }
{ "a": 1, "b": "YES" }
{ "a": 5, "b": "NOT" }
{ "a": 0, "b": "NOT" }
{ "a": 2, "b": "YES" }
You cannot only sort some items using the Array#sort() method - you either sort all or none. You don't define the position of the items, either - you only have to define their relationship to other items and the sorting algorithm will take care of the rest.
What you can do as a workaround is
Extract all items that should be sorted.
Sort them.
Go over the original array and only replace anything that should be sorted, leave the rest of the items in their place.
var a = [
{ a: 1, b: "YES" },
{ a: 2, b: "YES" },
{ a: 5, b: "NOT" },
{ a: 0, b: "NOT" },
{ a: 0, b: "YES" }
]
//get only `b: "YES"` items
const dataToSort = a.filter(item => item.b === "YES");
//sort them
dataToSort.sort((x, y) => x.a - y.a);
//replace only items that need to be sorted
const it = dataToSort.values()
for (let i = 0; i < a.length; i++) {
if (a[i].b === "NOT")
continue;
a[i] = it.next().value;
}
console.log(a);
For the record, the final loop can just be replaced with even shorter with more iterator usage, although it might be slightly more confusing:
const it = dataToSort.values()
for (const [key, item] of a.entries()) { //use the key-value iterator from the array
if (item.b === "NOT")
continue;
[a[key]] = it; //array destructuring internally advances an iterator
}
var a = [
{ a: 1, b: "YES" },
{ a: 2, b: "YES" },
{ a: 5, b: "NOT" },
{ a: 0, b: "NOT" },
{ a: 0, b: "YES" }
]
//get only `b: "YES"` items
const dataToSort = a.filter(item => item.b === "YES");
//sort them
dataToSort.sort((x, y) => x.a - y.a);
//replace only items that need to be sorted
const it = dataToSort.values()
for (const [key, item] of a.entries()) {
if (item.b === "NOT")
continue;
[a[key]] = it;
}
console.log(a);
Finally, this can be made somewhat more convenient with helper generator function and few small utility functions
/* library code */
const transformArg = transform => f => (...args) => f(transform(...args));
function* filter(predicate, it) {
for (const item of it) {
if (predicate(item))
yield item;
}
}
/* /library code */
var a = [
{ a: 1, b: "YES" },
{ a: 2, b: "YES" },
{ a: 5, b: "NOT" },
{ a: 0, b: "NOT" },
{ a: 0, b: "YES" }
]
/* helpers */
//extract the `b` key in this case so we don't need to repeat it.
const getSortableAttribute = transformArg(({b}) => b);
//get the value from key-value pair
const getValue = transformArg(([, value]) => value);
//check if the attribute is "YES"
const isSortable = getSortableAttribute(attr => attr === "YES");
const dataToSort = a.filter(isSortable);
dataToSort.sort((x, y) => x.a - y.a);
const it = dataToSort.values()
//iterate only over sortable key-value pairs by re-using the `isSortable` filter
for (const [key, item] of filter(getValue(isSortable), a.entries())) {
[a[key]] = it;
}
console.log(a);
This is an approach by using sort directly, but shaping the access with a Proxy for length and the indices.
const
sortOnly = (array, indices) => new Proxy(array, {
get (target, prop) {
if (isFinite(prop)) return target[indices[prop]];
if (prop === 'length') return indices.length;
return target[prop];
},
set (target, prop, receiver) {
target[indices[prop]] = receiver;
return true;
}
}),
array = [{ a: 1, b: "YES" }, { a: 2, b: "YES" }, { a: 5, b: "NOT" }, { a: 0, b: "NOT" }, { a: 0, b: "YES" }];
sortOnly(array, [...array.keys()].filter(i => array[i].b !== 'NOT'))
.sort((a, b) => a.a - b.a)
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }

object values spread into each other

I have const a = { _: { a: 1 }, __: { b: 2 }, ___: { c: 3 } }
How can I merge the object values of this object like so:
I want Result: { a:1, b: 2, c: 3}
You could assign the spreaded values.
const
a = { _: { a: 1 }, __: { b: 2 }, ___: { c: 3 } },
result = Object.assign({}, ...Object.values(a));
console.log(result);
You can use Object.values and reduce
const a = { _: { a: 1 }, __: { b: 2 }, ___: { c: 3 } }
let op = Object.values(a).reduce((op,inp) => ({...op,...inp}) ,{})
console.log(op)
On side note:- Keep in mind ... will make a shallow copy only if you more nested object you need to deep clone them

Using reduce to add values of properties of a collection objects in JavaScript

Pretty straight forward:
var bar = [
{ a: 10, b: 20 }, { a: 10, b: 20 }
];
var reduce = bar.reduce((acc, item) => {
acc['a'] = item.a++;
acc['b'] = item.b++
return acc;
}, {});
console.log(reduce);
{a: 10, b: 20}
I'd like reduce assigned the reference: {a:20, b: 40}
Here is a general solution that will work even if your object inside your array contains different properties.
var bar = [
{ a: 10, b: 20 }, { a: 10, b: 20 }
];
var reduce = bar.reduce((acc, item) => {
for (let [key, value] of Object.entries(item)){
if( acc.hasOwnProperty(key)) {
acc[key] += value
}
else {
acc = {...acc, [key]: value }
}
}
return acc;
}, {});
console.log(reduce);
Rather than assigning the accumulator's property the item's property incremented by one, you should add to the existing accumulator's property value. You also shouldn't pass an initial object to the reduce given this implementation (or, if you do, you'll need to define the a and b properties).
Since you're using reduce, I think you should also consider using const instead of var - const is less bug-prone and easier to read:
const bar = [
{ a: 10, b: 20 }, { a: 10, b: 20 }
];
const reduced = bar.reduce((acc, item) => {
acc.a += item.a;
acc.b += item.b;
return acc;
});
console.log(reduced);
You could return a new object with added values.
var bar = [{ a: 10, b: 20 }, { a: 10, b: 20 }],
reduce = bar.reduce((a, b) => ({ a: a.a + b.a, b: a.b + b.b }));
console.log(reduce);
Or with a complete dynamic approach for all properties.
const add = (a, b) =>
Object.assign({}, a, ...Object.entries(b).map(([k, v]) => ({ [k]: a[k] + v })));
var bar = [{ a: 10, b: 20 }, { a: 10, b: 20 }],
reduce = bar.reduce(add);
console.log(reduce);

Hot to use reduce to convert a array of objects to a single object

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

Categories