我认为这必须是一个副本,但我无法在SO上找到它。鉴于这样的对象:
let obj = { keyA: { keyB: 'hi', keyC: { keyD: null } }, keyE: 'hi' }
有没有办法找到给定值的关键路径,如下所示:
keyPaths(obj, 'hi') // -> [ 'keyA.keyB', 'keyE' ]
keyPaths(obj) // -> [ 'keyA.keyB.keyD' ]
我试图调整一些能够找到知识密钥的深层值的答案,而我几乎能够适应this one that finds deep nulls,但我无法弄清楚如何获得路径,而不仅仅是最深的密钥。
我会像这样深度搜索:
let obj = { keyA: { keyB: 'hi', keyC: { keyD: null } }, keyE: 'hi' }
function keyPaths(parent, value = null, chain) {
let allResults = [];
for (const prop in parent) {
if (parent.hasOwnProperty(prop)) {
const element = parent[prop];
const newChain = chain ? chain + '.' + prop : prop;
if (element === value) {
allResults.push(newChain);
}
else if (Object.keys(prop).length > 1) {
allResults = [...allResults, ...keyPaths(element, value, newChain)];
}
}
}
return allResults;
}
console.log(keyPaths(obj, 'hi')) // -> [ 'keyA.keyB', 'keyE' ]
console.log(keyPaths(obj)) // -> [ 'keyA.keyB.keyC' ]
基本上,我检查给定元素的所有属性以获得匹配值。如果属性与值不匹配,但具有子属性,则递归调用该函数,并合并调用迭代和递归调用的结果。
通过在递归函数中使用reduce
,您可以非常干净地完成此操作。该函数将返回一个数组,您可以将map()
返回到您想要的任何字符串值。
let obj = { keyA: { keyB: 'hi', keyC: { keyD: null } }, keyE: 'hi' }
function keyPaths(obj, val, path = [] ){
if (!obj) return
return Object.entries(obj).reduce((res, [k, v]) => {
let p = [...path, k]
if (v == val) res.push(p)
else if (v && typeof v == 'object') res.push(...keyPaths(v, val, p))
return res
}, [])
}
console.log(keyPaths(obj, 'hi').map(a => a.join('.')))
console.log(keyPaths(obj).map(a => a.join('|')))
如果可以使用Lodash + Deepdash,那么:
let paths = _(obj).filterDeep((v)=>v=='hi').paths().value();