Reputation: 2226
I have an object that originally looks like this
{
foo: {
fruit: "watermelon",
vege: "celery",
},
bar: {
fruit: "banana",
candy: "snickers",
drink: "coke",
},
...
}
but want to "flatten" and have it look like this
{
fruit: "banana",
vege: "celery",
candy: "snickers",
drink: "coke",
}
If there's an overlap in the sub-object keys, just overwrite the previous one.
What's a sane way to do this?
Upvotes: 0
Views: 1459
Reputation: 191986
With lodash you can use _.values()
that generates an array, and then spread to _.merge()
. I'm using _.flow()
to generate a function that does that:
const fn = _.flow(_.values, _.spread(_.merge))
const obj = {
foo: {
fruit: "watermelon",
vege: "celery",
},
bar: {
fruit: "banana",
candy: "snickers",
drink: "coke",
},
}
const result = fn(obj)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js" integrity="sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==" crossorigin="anonymous"></script>
Upvotes: 1
Reputation: 386654
You could take two function for getting a flat object from multi nested objects.
The outer gets from an array of objects a flat object and the recursinve function returns a flat array with object for every level.
const
flat = data => Object.assign({}, ...pairs(data)),
pairs = o => o && typeof o === 'object' && Object
.entries(o)
.flatMap(([k, v]) => pairs(v) || { [k]: v }),
data = {
foo: {
fruit: "watermelon",
vege: "celery"
},
bar: {
fruit: "banana",
candy: "snickers",
drink: "coke"
},
n: {
m: {
o: {
p: 42
}
}
}
},
result = flat(data);
console.log(result);
Upvotes: 0
Reputation: 50759
You can grab the values of your object using Object.values()
, and then use Object.assign()
with the spread syntax to merge all the objects together:
const obj = { foo: { fruit: "watermelon", vege: "celery", }, bar: { fruit: "banana", candy: "snickers", drink: "coke", } };
const res = Object.assign({}, ...Object.values(obj));
console.log(res);
With lodash you can use the corresponding methods _.assign()
and _.values()
:
const obj = { foo: { fruit: "watermelon", vege: "celery", }, bar: { fruit: "banana", candy: "snickers", drink: "coke", } };
const res = _.assign({}, ..._.values(obj));
console.log(res);
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
Both of these methods rely on the iteration order that Object.values()
and for...in
uses. In the latest spec this is something which can be relied on, but this hasn't always been the case. If you need to read the values in a guaranteed order 100% of the time, you can consider specifying the order of keys using an array:
const obj = { foo: { fruit: "watermelon", vege: "celery", }, bar: { fruit: "banana", candy: "snickers", drink: "coke", } };
const order = ["foo", "bar"]; // visit foo first then bar
const res = Object.assign({}, ...order.map(k => obj[k]));
console.log(res);
Upvotes: 4
Reputation: 8751
const input = {
foo: {
fruit: "watermelon",
vege: "celery",
},
bar: {
fruit: "banana",
candy: "snickers",
drink: "coke",
},
}
var result = {}
Object.values(input).forEach(item => {
result = {
...result,
...item
}
});
console.log(result)
Upvotes: 0
Reputation: 10194
You can get values of object using Object.prototype.values
and using Array.prototype.forEach
, you can get the merge the object [key, value]
pairs as follows.
const input = {
foo: {
fruit: "watermelon",
vege: "celery",
},
bar: {
fruit: "banana",
candy: "snickers",
drink: "coke",
}
};
let output = {};
Object.values(input).forEach((item) => {
output = {
...output,
...item
};
});
console.log(output);
Upvotes: 0