admin管理员组文章数量:1189789
I'm trying to flatten an object where the keys will be the full path to the leaf node. I can recursively identify which are the leaf nodes but stuck trying to construct the whole path.
Sample Input:
{ one: 1, two: { three: 3 }, four: { five: 5, six: { seven: 7 }, eight: 8 }, nine: 9 }
Output:
{ one: 1, 'two.three': 3, 'four.five': 5, 'four.six.seven': 7, 'four.eight': 8, nine: 9 }
I'm trying to flatten an object where the keys will be the full path to the leaf node. I can recursively identify which are the leaf nodes but stuck trying to construct the whole path.
Sample Input:
{ one: 1, two: { three: 3 }, four: { five: 5, six: { seven: 7 }, eight: 8 }, nine: 9 }
Output:
{ one: 1, 'two.three': 3, 'four.five': 5, 'four.six.seven': 7, 'four.eight': 8, nine: 9 }Share Improve this question asked Sep 17, 2016 at 13:09 SayemSayem 6,0994 gold badges23 silver badges27 bronze badges 5
- You can see this answer: stackoverflow.com/questions/19098797/… Hope it can help you. – Nguyen Tran Commented Sep 17, 2016 at 13:21
- Why do you want this? – Victor Commented Sep 17, 2016 at 14:03
- 1 @Victor I'm making api calls like api.moviestore.com/movies?where[movie.name:eq]=gravity. I need to flatten an object to construct the filter query. – Sayem Commented Sep 17, 2016 at 14:52
- @Sayem oh of course. I thought you just wanted to be able to get data by path or something. – Victor Commented Sep 17, 2016 at 14:54
- This question is too broad, because there are many possible solutions. Try to write the code yourself, and if you encounter any specific problem, ask about it. – Michał Perłakowski Commented Sep 17, 2016 at 17:19
10 Answers
Reset to default 16You could use a recursive approch and collect the keys of the object. This proposal looks for arrays as well.
function getFlatObject(object) {
function iter(o, p) {
if (o && typeof o === 'object') {
Object.keys(o).forEach(function (k) {
iter(o[k], p.concat(k));
});
return;
}
path[p.join('.')] = o;
}
var path = {};
iter(object, []);
return path;
}
var obj = { one: 1, two: { three: 3 }, four: { five: 5, six: { seven: 7 }, eight: 8 }, nine: 9 },
path = getFlatObject(obj);
console.log(path);
Partial solution : Give the input as a full path to the function and it gives you the respective output
var obj = {
one: 1,
two: {
three: 3
},
four: {
five: 5,
six: {
seven: 7
},
eight: 8
},
nine: 9
};
function deepFind(obj, path) {
var paths = path.split('.')
, current = obj
, i;
for (i = 0; i < paths.length; ++i) {
if (current[paths[i]] == undefined) {
return undefined;
} else {
current = current[paths[i]];
}
}
return current;
}
console.log(deepFind(obj, 'four.six.seven'))
Using newest JS features like Object spread and Object.entries
it should be pretty easy:
function flatObj(obj, path = []) {
let output = {};
Object.entries(obj).forEach(([ key, value ]) => {
const nextPath = [ ...path, key ];
if (typeof value !== 'object') {
output[nextPath.join('.')] = value;
return;
}
output = {
...output,
...flatObj(value, nextPath)
};
});
}
Please note that this code is probably not the most optimal one as it copies the object each time we want to merge it. Treat it more as a gist of what would it look like, rather than a complete and final solution.
var obj = {
one: 1,
two: {
three: 3
},
four: {
five: 5,
six: {
seven: 7
},
eight: 8
},
nine: 9
};
function flatten(obj) {
var flatObj = {}
function makeFlat(obj, path) {
var keys = Object.keys(obj);
if (keys.length) {
keys.forEach(function (key) {
makeFlat(obj[key], (path ? path + "." : path) + key);
})
} else {
flatObj[path] = obj;
}
}
makeFlat(obj, "");
return flatObj;
}
console.log(flatten(obj));
A non fancy approach, internally uses recursion.
var x = { one:1,two:{three:3},four:{five: 5,six:{seven:7},eight:8},nine:9};
var res = {};
var constructResultCurry = function(src){ return constructResult(res,src); }
function constructResult(target, src) {
if(!src) return;
target[src.key] = src.val;
}
function buildPath(key, obj, overAllKey) {
overAllKey += (overAllKey ? "." : "") + key;
if(typeof obj[key] != "object") return { key : overAllKey, val : obj[key] };
Object.keys(obj[key]).forEach(function(keyInner) {
constructResultCurry(buildPath(keyInner, obj[key], overAllKey));
});
}
Object.keys(x).forEach(function(k){
constructResultCurry(buildPath(k, x, ""));
});
console.log(res);
You might simply do as follows;
var obj = {one: 1, two: {three: 3}, four: {five: 5, six: {seven: 7}, eight: 8}, nine: 9},
flatObj = (o,p="") => { return Object.keys(o)
.map(k => o[k] === null ||
typeof o[k] !== "object" ? {[p + (p ? ".":"") + k]:o[k]}
: flatObj(o[k],p + (p ? ".":"") + k))
.reduce((p,c) => Object.assign(p,c));
};
console.log(flatObj(obj));
I find a tiny JavaScript utility to access properties using path. It is called object-path and is an opensource project on GitHub.
To get attribute from an object:
objectPath.get(obj, "a.b");
to set attribute:
objectPath.set(obj, "a.b", value);
to remove an attribute:
objectPath.del(obj, "a.b");
So easy!!
You can achieve it by using this function:
const obj = {
one: 1,
two: {
three: 3
},
four: {
five: 5,
six: {
seven: 7
},
eight: 8
},
nine: 9
}
const flatObject = (obj, keyPrefix = null) =>
Object.entries(obj).reduce((acc, [key, val]) => {
const nextKey = keyPrefix ? `${keyPrefix}.${key}` : key
if (typeof val !== "object") {
return {
...acc,
[nextKey]: val
};
} else {
return {
...acc,
...flatObject(val, nextKey)
};
}
}, {});
console.log(flatObject(obj))
Here is an interative solution using object-scan.
object-scan
is a data processing tool, so the main advantage here is that it would be easy to do further processing or processing while extracting the desired information
// const objectScan = require('object-scan');
const myData = { one: 1, two: { three: 3 }, four: { five: 5, six: { seven: 7 }, eight: 8 }, nine: 9 };
const flatten = (data) => {
const entries = objectScan(['**'], {
reverse: false,
rtn: 'entry',
joined: true,
filterFn: ({ isLeaf }) => isLeaf
})(data);
return Object.fromEntries(entries);
};
console.log(flatten(myData));
// => { one: 1, 'two.three': 3, 'four.five': 5, 'four.six.seven': 7, 'four.eight': 8, nine: 9 }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>
Disclaimer: I'm the author of object-scan
Try this
let x;
try{
x = JSON.parse(prompt("Input your JSON"))
}
catch(e) {
alert("not a valid json input")
}
var res = {};
var constructResultCurry = function(src){ return constructResult(res,src); }
function constructResult(target, src) {
if(!src) return;
target[src.key] = src.val;
}
function buildPath(key, obj, overAllKey) {
overAllKey += (overAllKey ? "." : "") + key;
if(typeof obj[key] != "object") return { key : overAllKey, val : obj[key] };
Object.keys(obj[key]).forEach(function(keyInner) {
constructResultCurry(buildPath(keyInner, obj[key], overAllKey));
});
}
Object.keys(x).forEach(function(k){
constructResultCurry(buildPath(k, x, ""));
});
console.log("**************ALL FIELDS****************")
console.log(res);
console.log("******************************************")
let conf = confirm("do you need a specific field from JSON");
if ( conf )
{
let field = prompt("Input field name")
let results = Object.fromEntries(
Object.entries(res).filter(([key]) => (key.toLowerCase()).includes((field.toLowerCase()))))
prompt("Copy to clipboard: Ctrl+C, Enter", JSON.stringify(results));
console.log(results)
}
else {
prompt("Copy to clipboard: Ctrl+C, Enter", JSON.stringify(res));
}
https://jsfiddle.net/amars404/2n9fprz8/57/
本文标签: javascriptFull path of a json objectStack Overflow
版权声明:本文标题:javascript - Full path of a json object - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1738417755a2085682.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论