Sorry I don't know how to phrase the question title. Please help edit if possible.
I have an object like this:
{
a: 'jack',
b: {
c: 'sparrow',
d: {
e: 'hahaha'
}
}
}
I want to make it look like:
{
'a': 'jack',
'b.c': 'sparrow',
'b.d.e': 'hahaha'
}
// so that I can use it this way:
a['b.d.e']
jQuery is ok too. I know for the nested object, I can use abde
to get hahaha
, but today I have to use it like a['bde']
-_-!!! How can I achieve this? Thanks in advance :)
You could use a recursive function to crawl the object and flatten it for you.
var test = { a: 'jack', b: { c: 'sparrow', d: { e: 'hahaha' } } }; function traverseAndFlatten(currentNode, target, flattenedKey) { for (var key in currentNode) { if (currentNode.hasOwnProperty(key)) { var newKey; if (flattenedKey === undefined) { newKey = key; } else { newKey = flattenedKey + '.' + key; } var value = currentNode[key]; if (typeof value === "object") { traverseAndFlatten(value, target, newKey); } else { target[newKey] = value; } } } } function flatten(obj) { var flattenedObject = {}; traverseAndFlatten(obj, flattenedObject); return flattenedObject; } var flattened = JSON.stringify(flatten(test)); console.log(flattened);
An alternative recursive implementation. I just felt like writing one implementation myself, even though the current ones are already really good.
The recursive function checks whether the key is of type 'object'
.
function flat(res, key, val, pre = '') {
const prefix = [pre, key].filter(v => v).join('.');
return typeof val === 'object'
? Object.keys(val).reduce((prev, curr) => flat(prev, curr, val[curr], prefix), res)
: Object.assign(res, { [prefix]: val});
}
return Object.keys(input).reduce((prev, curr) => flat(prev, curr, input[curr]), {});
Or you can simply use flat npm package , which is a well known tested library.
var flatten = require('flat')
flatten(obj);
⬑ I would use this in serious code.
function flatObject(input) {
function flat(res, key, val, pre = '') {
const prefix = [pre, key].filter(v => v).join('.');
return typeof val === 'object'
? Object.keys(val).reduce((prev, curr) => flat(prev, curr, val[curr], prefix), res)
: Object.assign(res, { [prefix]: val});
}
return Object.keys(input).reduce((prev, curr) => flat(prev, curr, input[curr]), {});
}
const result = flatObject(input);
http://codepen.io/zurfyx/pen/VpErja?editors=1010
function flatObject(input) { function flat(res, key, val, pre = '') { const prefix = [pre, key].filter(v => v).join('.'); return typeof val === 'object' ? Object.keys(val).reduce((prev, curr) => flat(prev, curr, val[curr], prefix), res) : Object.assign(res, { [prefix]: val}); } return Object.keys(input).reduce((prev, curr) => flat(prev, curr, input[curr]), {}); } const result = flatObject({ a: 'jack', b: { c: 'sparrow', d: { e: 'hahaha' } } }); document.getElementById('code').innerHTML = JSON.stringify(result, null, 2);
<pre><code id="code"></code></pre>
You could loop through the entries of the object. If the value
is an object, recursively call the function. Use flatMap
to get a flattened array of entries.
Then use Object.fromEntries()
to get an object from the flattened array of entries
const input = { a: 'jack', b: { c: 'sparrow', d: { e: 'hahaha' } } } const getEntries = (o, prefix = '') => Object.entries(o).flatMap(([k, v]) => Object(v) === v ? getEntries(v, `${prefix}${k}.`) : [ [`${prefix}${k}`, v] ] ) console.log( Object.fromEntries(getEntries(input)) )
Note : Object(v) === v
returns true
only for objects. typeof v === 'object'
is true for v = null
too.
Recursive is the best solution for this case.
function flatten(input, reference, output) { output = output || {}; for (var key in input) { var value = input[key]; key = reference ? reference + '.' + key : key; if (typeof value === 'object' && value !== null) { flatten(value, key, output); } else { output[key] = value; } } return output; } var result = flatten({ a: 'jack', b: { c: 'sparrow', d: { e: 'hahaha' } } }); document.body.textContent = JSON.stringify(result);
Option 1: export a flat object with just the Leaves. ie object exported contains just paths with primitive value at the end ( see example ) .
//recursion: walk on each route until the primitive value.
//Did we found a primitive?
//Good, then join all keys in the current path and save it on the export object.
export function flatObject(obj) {
const flatObject = {};
const path = []; // current path
function dig(obj) {
if (obj !== Object(obj))
/*is primitive, end of path*/
return flatObject[path.join('.')] = obj; /*<- value*/
//no? so this is an object with keys. go deeper on each key down
for (let key in obj) {
path.push(key);
dig(obj[key]);
path.pop();
}
}
dig(obj);
return flatObject;
}
Example
let obj = {aaa:{bbb:{c:1,d:7}}, bb:{vv:2}}
console.log(flatObject(obj))
/*
{
"aaa.bbb.c": 1,
"aaa.bbb.d": 7,
"bb.vv": 2
}
*/
Option 2: export a flat object with all intermidate paths . a little bit shorter and simpler (see example).
export function flatObject(obj) {
const flatObject = {};
const path = []; // current path
function dig(obj) {
for (let key in obj) {
path.push(key);
flatObject[path.join('.')] = obj[key];
dig(obj[key])
path.pop();
}
}
dig(obj);
return flatObject;
}
Example :
let obj = {aaa:{bbb:{c:1,d:7}}, bb:{vv:2}}
console.log(flatObject(obj))
/*{
"aaa": {
"bbb": {
"c": 1,
"d": 7
}
},
"aaa.bbb": {
"c": 1,
"d": 7
},
"aaa.bbb.c": 1,
"aaa.bbb.d": 7,
"bb": {
"vv": 2
},
"bb.vv": 2
}
*/
A recursive approach by using a parameter for parent keys.
const getValues = (object, parents = []) => Object.assign({}, ...Object .entries(object) .map(([k, v]) => v && typeof v === 'object' ? getValues(v, [...parents, k]) : { [[...parents, k].join('.')]: v } ) ), object = { a: 'jack', b: { c: 'sparrow', d: { e: 'hahaha' } } }; console.log(getValues(object));
Just an example how can you achieve that with ES6 features.
const flatObject = obj => {
const keys = Object.keys(obj)
return keys.reduce((acc, k) => {
const value = obj[k]
return typeof value === 'object' ?
{...acc, ...ObjectUtils.flatObject(value)} :
{...acc, [k]: value}
} , {})
}
Another approach using ES6.
const obj = {
a: "jack",
b: {
c: "sparrow",
d: {
e: "hahaha"
}
}
};
function flattenObj(value, currentKey) {
let result = {};
Object.keys(value).forEach(key => {
const tempKey = currentKey ? `${currentKey}.${key}` : key;
if (typeof value[key] !== "object") {
result[tempKey] = value[key];
} else {
result = { ...result, ...flattenObj(value[key], tempKey) };
}
});
return result;
}
console.log(flattenObj(obj));
Here is a simple solution -
function flatObj(obj, newObj, parentKey) {
for(let key in obj) {
const currKey = parentKey.length > 0 ? `${parentKey}.${key}` : key
if (typeof obj[key] === "object") {
flatObj(obj[key], newObj, currKey);
} else {
newObj[currKey] = obj[key];
}
}
return newObj;
};
let obj = {
a: 'jack',
b: {
c: 'sparrow',
d: {
e: 'hahaha'
}
}
};
console.log(flatObj(obj, {}, ""));
var flattenObject = function(ob) { var toReturn = {}; for (var i in ob) { if (!ob.hasOwnProperty(i)) continue; if ((typeof ob[i]) == 'object' && ob[i] !== null) { var flatObject = flattenObject(ob[i]); for (var x in flatObject) { if (!flatObject.hasOwnProperty(x)) continue; toReturn[i + '.' + x] = flatObject[x]; } } else { toReturn[i] = ob[i]; } } console.log(toReturn) return toReturn; }; var ob = { 'a': { 'b': { 'b2': 2 }, 'c': { 'c2': 2, 'c3': 3 } } }; flattenObject(ob);
const flatten = function(obj) {
const result = {};
for (let key in obj) {
if (typeof obj[key] === 'object') {
const childObj = flatten(obj[key]);
for (let childObjKey in childObj) {
result[`${key}.${childObjKey}`] = childObj[childObjKey];
}
} else {
result[key] = obj[key];
}
}
return result
}
var test = {
a: 'jack',
b: {
c: 'sparrow',
d: {
e: 'hahaha'
}
}
};
console.log(flatten(test));
If you are here to convert nested object like this
{
a:2,
b: {
c:3
}
}
to this
{
a:2,
c:3
}
than try this Object.assign one line to flat the nested object
Object.assign({}, ...function _flatten(o) { return [].concat(...Object.keys(o).map(k => typeof o[k] === 'object' ? _flatten(o[k]) : ({[k]: o[k]})))}(yourObject))
reference to this post
尝试这个
const result = [].concat.apply([], parentArray.map((item: any) => item.any)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.