Fastest way to flatten / un-flatten nested JavaScript objects
Here's my much shorter implementation:
Object.unflatten = function(data) {
"use strict";
if (Object(data) !== data || Array.isArray(data))
return data;
var regex = /\.?([^.\[\]]+)|\[(\d+)\]/g,
resultholder = {};
for (var p in data) {
var cur = resultholder,
prop = "",
m;
while (m = regex.exec(p)) {
cur = cur[prop] || (cur[prop] = (m[2] ? [] : {}));
prop = m[2] || m[1];
}
cur[prop] = data[p];
}
return resultholder[""] || resultholder;
};
flatten
hasn't changed much (and I'm not sure whether you really need those isEmpty
cases):
Object.flatten = function(data) {
var result = {};
function recurse (cur, prop) {
if (Object(cur) !== cur) {
result[prop] = cur;
} else if (Array.isArray(cur)) {
for(var i=0, l=cur.length; i<l; i++)
recurse(cur[i], prop + "[" + i + "]");
if (l == 0)
result[prop] = [];
} else {
var isEmpty = true;
for (var p in cur) {
isEmpty = false;
recurse(cur[p], prop ? prop+"."+p : p);
}
if (isEmpty && prop)
result[prop] = {};
}
}
recurse(data, "");
return result;
}
Together, they run your benchmark in about the half of the time (Opera 12.16: ~900ms instead of ~ 1900ms, Chrome 29: ~800ms instead of ~1600ms).
Note: This and most other solutions answered here focus on speed and are susceptible to prototype pollution and shold not be used on untrusted objects.
One liner to flatten nested object
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)
)
Flatten nested objects, keeping the properties of parents
You could have a look to the arrays and if no objects inside return an object, otherwise map val
property by storing other properties.
const
isObject = o => o && typeof o === 'object',
flat = array => {
if (!array.every(isObject)) return { val: array };
return array.flatMap(({ val, ...o }) => {
const temp = flat(val);
return Array.isArray(temp)
? temp.map(t => ({ ...o, ...t }))
: { ...o, ...temp };
});
},
data0 = [{ a: "x", val: [{ b: "y1", val: [1, 2, 3] }, { b: "y2", val: [4, 5, 6] }] }],
data1 = [{ a: "x", val: [{ b: "y1", val: [{ c: "z1", val: [1, 2] }] }, { b: "y2", val: [{ c: "z2", val: [3, 4] }, { c: "z3", val: [5, 6, 7] }, { c: "z4", val: [8] }] }] }];
console.log(flat(data0));
console.log(flat(data1))
.as-console-wrapper { max-height: 100% !important; top: 0; }
What's an efficient way to flatten/un-nest a nested object with an unknown level of nesting?
You could use (upcoming) Array#flatMap
and get objects without children.
const untree = ({ children = [], ...data }) => [data, ...children.flatMap(untree)];
var tree = [{ title: "parent1", id: "1", children: [{ title: "child 1", id: 2, parentid: 1 }, { title: "child 2", id: 3, parentid: 1 }] }, { title: "parent 2", id: 4, children: [{ title: "child 1", id: 5, parentid: 4, children: [{ title: "GRAND CHILD", id: 6, parentid: 5 }] }] }],
result = tree.flatMap(untree);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Recursively flatten a deeply-nested mix of objects and arrays
Here's a simple recursion:
const deepKeys = (o) =>
Array .isArray (o)
? o .flatMap (deepKeys)
: Object (o) === o
? Object .entries (o) .flatMap (([k, v]) => [k, ... deepKeys (v)])
: []
const sampleData = {coyotes: '', armadillos: false, wombats: [''], geckos: 0, dogs: {beagle: '', bulldog: ''}, wolves: [{type: '', color: '', range: '', status: {endangered: true, protected: false}}], cats: {}}
console .log (deepKeys (sampleData))
.as-console-wrapper {max-height: 100% !important; top: 0}
Attempting to flatten nested objects based on a specific field key
You can combine Array#map
and Array#reduce
to achieve the desired output.
const mapped = data.map(({ scores, ...rest }) => ({
...rest,
...scores.reduce((output, score) => ({ ...output, [score.id]: score.score }), {})
}));
Angular: Flatten / un-flatten nested JSON objects
The answer is no. Angular doesn't have that, but RxJs could have something that you can find useful.
Best way to "flatten" an array inside an RxJS Observable
http://alanpryorjr.com/2019-05-15-rxjs-flattening-operators/
Best way to flatten JS object (keys and values) to a single depth array
You could just concat all keys and values. (It does not solve the type casting to number for keys.)
var object = { 0: [1, 2, 3, 4] },
result = Object.keys(object).reduce(function (r, k) {
return r.concat(k, object[k]);
}, []);
console.log(result);
How to flatten a JavaScript object into a daisy chain like form?
You can create recursive function like this, and its important to store previous keys in one string.
var obj1 = {
firstName: 'John',
lastName: 'Green',
car: {
make: 'Honda',
model: 'Civic',
revisions: [
{ miles: 10150, code: 'REV01', changes: 0},
{ miles: 20021, code: 'REV02', changes: [
{ type: 'asthetic', desc: 'Left tire cap' },
{ type: 'mechanic', desc: 'Engine pressure regulator' }
] }
]
},
visits: [
{ date: '2015-01-01', dealer: 'DEAL-001' },
{ date: '2015-03-01', dealer: 'DEAL-002' }
]
};
function flatten(data, c) {
var result = {}
for(var i in data) {
if(typeof data[i] == 'object') Object.assign(result, flatten(data[i], c + '.' + i))
else result[(c + '.' + i).replace(/^\./, "")] = data[i]
}
return result
}
console.log(JSON.stringify(flatten(obj1, ''), 0, 4))
Related Topics
Weird Behavior With Objects & Console.Log
JavaScript by Reference Vs. by Value
How to Pad a Value With Leading Zeros
Http Get Request in JavaScript
Onclick or Inline Script Isn't Working in Extension
How to Detect If a Browser Window Is Not Currently Active
How to Return Many Promises and Wait For Them All Before Doing Other Stuff
What Is the Purpose of a Self Executing Function in JavaScript
Sorting in JavaScript: Shouldn't Returning a Boolean Be Enough For a Comparison Function
Does Es6 Introduce a Well-Defined Order of Enumeration For Object Properties
Setstate Doesn't Update the State Immediately
JavaScript Function Scoping and Hoisting
How to Manage a Redirect Request After a Jquery Ajax Call
Parsing a String to a Date in JavaScript
Firebase Query If Child of Child Contains a Value
Difference Between ( For... in ) and ( For... of ) Statements