Merge nested array of objects by comparing key [duplicate] - javascript

This question already has answers here:
How can I merge properties of two JavaScript objects dynamically?
(69 answers)
Closed 9 months ago.
I have an 3 nested array of Objects and I need to merge them all in single array of objects by comparing key. and if any object have same key then their inner object will merge. And if key is not same then also the nested array of objects will merge*
var obj1 = {
a: {
c: 3
}
}
var obj2 = {
b: {
e: 40
}
}
var obj3 = {
d: {
x: 30
},
a: {
f: 66
}
}
// The expected output will be like this -
//
/*OUTPUT:::
{
a: {
c: 3,
f: 66
},
b: {
e: 40
},
d: {
x: 30
}
}
Please tell me which approach would be suitable ?

You can group the objects using Array.prototype.reduce.
const
obj1 = { a: { c: 3 } },
obj2 = { b: { e: 40 } },
obj3 = { d: { x: 30 }, a: { f: 66 } };
const res = [obj1, obj2, obj3].reduce((r, o) => {
Object.entries(o).forEach(([k, v]) => {
r[k] = { ...r[k], ...v };
});
return r;
}, {});
console.log(res);

Related

How to get values from these objects [duplicate]

This question already has answers here:
One liner to flatten nested object
(19 answers)
Closed 1 year ago.
I am trying to achieve it Like a:1,b:2:,c:3,e:4,g:5,h:6
But not getting success.
Facing error this. But is the best way to do it.
const input = {
a: 1,
b: 2,
c: 3,
d: {
e: 4,
f: {
g: 5,
h: 6
}
}
}
const getValue = (values) => {
for (let i in Object.keys(values)) {
if (Object.keys(values[Object.keys(values)[i]]).length > 0) {
console.log('v', Object.keys(values)[i])
getValue(Object.keys(values)[i])
} else {
// console.log(Object.keys(values)[i],Object.values(values)[i])
}
}
}
getValue(input)
You can iterate through each key of object and for object value recursively call your getValue() function.
const input = { a:1, b:2, c:3, d:{ e:4, f:{ g:5, h:6 } } }
const getValue = (values) => {
for (const key of Object.keys(values)) {
if(typeof values[key] === 'object' && values[key] !== null) {
getValue(values[key]);
} else {
console.log(`${key}: ${values[key]}`);
}
}
}
getValue(input);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could use recursion to get the desired result.
const input = {
a: 1,
b: 2,
c: 3,
d: {
e: 4,
f: {
g: 5,
h: 6,
},
},
};
const result = {};
function getValues(obj) {
for (let key in obj) {
if (typeof obj[key] !== `object`) result[key] = obj[key];
else getValues(obj[key]);
}
}
getValues(input);
console.log(result);
Edited : you can do something like this
const input = {a:1,b:2,c:3,d:{e:4,f:{g:5,h:6 }}}
Object.assign({}, ...function _flatten(o) { return [].concat(...Object.keys(o).map(k => typeof o[k] === 'object' ? _flatten(o[k]) : ({[k]: o[k]})))}(input))
//{a: 1, b: 2, c: 3, e: 4, g: 5, …}
you can see more details here

How to flatten object of objects recursively into array

I have an object like this:
const myObj = {
a: {
b: {
c: 1,
d: 2
},
f: {
z: 4,
u: 6
}
}
}
into this:
const myObj = [
{
c: 1,
d: 2,
},
{
z: 4,
u: 6,
}
]
I found this: How to recursively transform an array of nested objects into array of flat objects? but the original is an array of objects, and mine is an object itself.
You can traverse the values of the objects until you reach the leaves (objects with no values that are other objects).
const myObj = {
a: {
b: {
c: 1,
d: 2
},
f: {
z: 4,
u: 6
}
}
};
const flatObj = o => Object.values(o).some(x => x === Object(x)) ?
Object.values(o).flatMap(flatObj) : [o];
console.log(flatObj(myObj))

access nested object values dynamically using JavaScript [duplicate]

This question already has answers here:
Accessing nested JavaScript objects and arrays by string path
(44 answers)
Closed 2 years ago.
Assume I have an object:
var abc = {
a: 'a',
b: 'b',
c: {
x: 'c',
y: 'd'
}
}
Now I want to fetch object values based on values present in an array below dynamically
var arr = ['a', 'b', 'c.x']
NOTE: the following solution would work with the given scenario, where object properties are indicated using the dot notation, but will fail if you use bracket notation (e.g. c[x]).
const abc = {
a: 'aVal',
b: 'bVal',
c: {
x: 'cxVal',
y: 'cyVal'
},
d: {
x: 'dxVal',
y: {
z: 'dyzVal',
w: 'dywVal'
}
}
};
const arr = ['a', 'b', 'c.x', 'd.y.w'];
function getValues(obj, keysArr) {
return keysArr.map(key => {
return key.split('.').reduce((acc, item) => {
return acc[item];
}, obj);
});
}
const values = getValues(abc, arr);
console.log(values);
You can create an extension like this:
Object.defineProperty(Object.prototype, 'valueAt', {
value: function (location, defaultValue) {
const routes = location.split('.');
const lastRoute = routes.pop();
let value = routes.reduce(
(current, route) => current && current[route],
this
);
if (value) return value[lastRoute] || defaultValue;
else return defaultValue;
},
writable: true,
configurable: true,
enumerable: false,
});
and then use:
abc.valueAt("c.x");
You could split the strings for getting an array and reduce the keys by accessing the object.
var getValue = (object, keys) => keys.reduce((o, k) => (o || {})[k], object),
object = { a: 'a', b: 'b', c: { x: 'c', y: 'd' } },
keys = ['a', 'b', 'c.x'],
result = keys.map(s => getValue(object, s.split('.')));
console.log(result);

How to group by the same key in a collection [duplicate]

This question already has answers here:
How can I group an array of objects by key?
(32 answers)
Closed 3 years ago.
Assume the following objects
let oldArr = [
{ a: 1 },
{ a: 2 },
{ a: 3 },
{ b: 1 },
{ b: 2 },
{ c: 1 }
]
Desired result
let newArr = [
[
{ a: 1 },
{ a: 2 },
{ a: 3 },
],
[
{ b: 1 },
{ b: 2 },
],
[
{ c: 1 }
],
]
I try to use lodash, I see the partition function but it only splits the arrays into 2 groups. The groupBy groups it into an object by keys.
Is there any good way? hope to get everyone's help, thank you!
you can do this using Object.keys, Object.values and Array.reduce
let oldArr = [
{ a: 1 },
{ a: 2 },
{ a: 3 },
{ b: 1 },
{ b: 2 },
{ c: 1 },
{ a: 4, c: 2 }
]
let newArr =
// drop the keys of the object created by the reduce
Object.values(
// for each object in the array
oldArr.reduce((acc, el) => {
// for each keys in the object
Object.keys(el).forEach(key => {
// add the object to the group of objects with this key
acc[key] = acc[key] || []
acc[key].push(el)
})
return acc
}, {})
)
console.log(newArr)
if an object in the input have multiple keys it will go to each group in the output
Simply like this:
let oldArr = [
{ a: 1 },
{ a: 2 },
{ a: 3 },
{ b: 1 },
{ b: 2 },
{ c: 1 }
]
let objects = {};
for (let item of oldArr) {
// get key
let key = Object.keys(item)[0];
// check if this key added before
if (!objects[key]) objects[key] = [];
// push this object
objects[key].push(item);
}
let newArr = Object.values(objects);
console.log(newArr)
But you should be sure that every object in oldArr has only one key.
you can use like that
let oldArr = [
{ a: 1 },
{ a: 2 },
{ a: 3 },
{ b: 1 },
{ b: 2 },
{ c: 1 }
];
let newArr = {};
oldArr.forEach((i)=>{
let key = Object.keys(i)[0];
newArr[key] = newArr[key] || [];
newArr[key].push(i);
});
newArr = Object.values(newArr);
console.log(newArr);

Flatten array with objects into 1 object

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.

Categories

Resources