Here you go:
Object.assign({}, ...function _flatten(o) { return [].concat(...Object.keys(o).map(k => typeof o[k] === 'object' ? _flatten(o[k]) : ({[k]: o[k]})))}(yourObject))
Summary: recursively create an array of one-property objects, then combine them all with Object.assign.
This uses ES6 features including Object.assign or the spread operator, but it should be easy enough to rewrite not to require them.
For those who don't care about the one-line craziness and would prefer to be able to actually read it (depending on your definition of readability):
Object.assign(
{},
...function _flatten(o) {
return [].concat(...Object.keys(o)
.map(k =>
typeof o[k] === 'object' ?
_flatten(o[k]) :
({[k]: o[k]})
)
);
}(yourObject)
)
Answer from user663031 on Stack OverflowHere you go:
Object.assign({}, ...function _flatten(o) { return [].concat(...Object.keys(o).map(k => typeof o[k] === 'object' ? _flatten(o[k]) : ({[k]: o[k]})))}(yourObject))
Summary: recursively create an array of one-property objects, then combine them all with Object.assign.
This uses ES6 features including Object.assign or the spread operator, but it should be easy enough to rewrite not to require them.
For those who don't care about the one-line craziness and would prefer to be able to actually read it (depending on your definition of readability):
Object.assign(
{},
...function _flatten(o) {
return [].concat(...Object.keys(o)
.map(k =>
typeof o[k] === 'object' ?
_flatten(o[k]) :
({[k]: o[k]})
)
);
}(yourObject)
)
Simplified readable example, no dependencies
/**
* Flatten a multidimensional object
*
* For example:
* flattenObject{ a: 1, b: { c: 2 } }
* Returns:
* { a: 1, c: 2}
*/
export const flattenObject = (obj) => {
const flattened = {}
Object.keys(obj).forEach((key) => {
const value = obj[key]
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
Object.assign(flattened, flattenObject(value))
} else {
flattened[key] = value
}
})
return flattened
}
Features
- No dependencies
- Works with null values
- Works with arrays
- Working example https://jsfiddle.net/webbertakken/jn613d8p/26/
Videos
» npm install flatten-object
You can try to do it with Array.reduce. It is better than original code because of 2 points:
- We don't need to create an additional variable to show answer (
newArrin my example is just for clear code, we can also not to use it andconsole.logthe result directly) - In original code we use
array.mapmethod to save the "mutated" array in another variable and then destructing it so we have 2 loops. But we can do it with 1 loop, we just need to get each item in array and put it to another array without saving it anywhere
So I think that my example is less complex and faster.
P.S. I also think that we don't need pretty variable.
const content = [
{ role: 'row', id: 0, expressions: { formula: [ { id: 'L34', name: 'CommodityName' }, { id: 'L4', name: 'ItemId' } ] } },
{ role: 'column', id: 1, expressions: { formula: [ { id:'LC', name: 'Year' }, { id: 'LA', name: 'Month' } ] } },
{ role: 'body', id: 2, expressions: { formula: [ { id:'L1B', name: 'Demand' } ] } }
];
const newArr = content.reduce((formulas, contentItem) => {
contentItem.expressions.formula.forEach(formulaItem => formulas.push({
contentId: contentItem.id,
role: contentItem.role,
...formulaItem
}));
return formulas;
}, [])
console.log(newArr);
The original version is clear, but you can avoid the unnecessary mutation and assign to formulas in a single statement using a flat map.
const formulas = content.flatMap(o =>
o.expressions.formula.map(
(x) => ({ contentId: o.id, role: o.role, ...x })
)
)
For older versions of JS that don't have the flatMap built in, there is a flat map idiom using Array.concat:
[].concat(...x.map(f))
where x.map(f) returns a possible nested array. This will flatten the array 1 level, which is typically all you need.
In your case, this becomes:
const formulas = [].concat(
...content.map(o => o.expressions.formula.map(
(x) => ({ contentId: o.id, role: o.role, ...x })
))
)
» npm install flatten-anything