javascript - 查找嵌套对象中所有匹配键值的路径
问题描述
我有一个函数可以让我找到第一次找到键和值匹配的嵌套对象的路径。
function getPath(obj, givenKey, givenValue) {
for(var key in obj) {
if(obj[key] && typeof obj[key] === "object") {
var result = getPath(obj[key], givenValue, givenKey);
if(result) {
result.unshift(key)
return result;
}
} else if(obj[key] === givenValue && key === givenKey ) {
return [key];
}
}
}
样本数据
var myObj = [
{
"name": "needle",
"children": [
{
"name": "group2",
"children": [
{
"name": "item0"
}]
}]
},
{
"name": "item1"
},
{
"name": "needleGroup",
"children": [
{
"name": "needleNestedGroup",
"children": [
{
"name": "item3"
},
{
"name": "needleNestedDeeperGroup",
"children": [
{
"name": "needle"
}]
}]
}]
}];
预期产出
getPath(myObj, "name", "needle"):
[0, "name"]
["2","children","0","children","1","children","0","name"]
但是,我现在有一个多次包含这些键值的对象,所以我有多个匹配项。
我怎样才能将它们全部放在一个数组中?我当前的功能在找到第一个匹配项后才停止。事实上,它是递归的,这让我的事情变得非常复杂
解决方案
我将把它写在一个更通用的findAllPaths
函数之上,该函数接受一个谓词并找到对象中与该谓词匹配的所有节点的路径。有了它,那么findPathsByName
就很简单了(target) => findAllPaths (({name}) => name == target)
。
反过来,我建立findAllPaths
在我一直使用的pathEntries
变体之上。此函数将对象转换为路径/值对数组。有些版本只生成叶子节点。这个为所有节点生成它,包括根(有一个空路径)。这个函数的基本思想是变成这样的:
{a: 'foo', b: {c: ['bar', 'baz'], f: 'qux'}}
进入这个:
[
[[], {a: 'foo', b: {c: ['bar', 'baz'], f: 'qux'}}],
[['a'], 'foo'],
[['b'], {c: ['bar', 'baz'], f: 'qux'}],
[['b', 'c'], ['bar', 'baz']],
[['b', 'c', 0], 'bar'],
[['b', 'c', 1], 'baz'],
[['b', 'f'], 'qux']
]
其中每个子数组中的第一项是路径,第二项是对该路径的值的引用。
下面是它的样子:
const pathEntries = (obj) => [
[[], obj],
...Object (obj) === obj
? Object .entries (obj) .flatMap (
([k, x]) => pathEntries (x) .map (
([p, v]) => [[Array .isArray (obj) ? Number (k) : k, ... p], v]
)
)
: []
]
const findAllPaths = (predicate) => (o) =>
[...pathEntries (o)] .filter (([p, v]) => predicate (v, p)) .map (([p]) => p)
const findPathsByName = (target) => findAllPaths (({name}) => name == target)
const myObj = [{name: "needle", children: [{name: "group2", children: [{name: "item0"}]}]}, {name: "item1"}, {name: "needleGroup", children: [{name: "needleNestedGroup", children: [{name: "item3"}, {name: "needleNestedDeeperGroup", children: [{name: "needle"}]}]}]}]
console .log (findPathsByName ('needle') (myObj))
.as-console-wrapper {max-height: 100% !important; top: 0}
该问题要求数组索引的字符串值。我自己更喜欢这里的整数值,但是你稍微简化了函数:
- ([p, v]) => [[Array .isArray (obj) ? Number (k) : k, ... p], v]
+ ([p, v]) => [[k, ... p], v]
推荐阅读
- html - Css ::after 与使用 Twig 应用的链接文本未显示在同一行上
- ios - 在自己的应用程序/视图中接收本地通知(或如何在 SwiftUI 中注册 UNUserNotificationCenterDelegate)
- javascript - 如何将 JSON 变量传递给 Vue App + Components
- delphi - 从 Delphi 代码调出表情符号面板
- javascript - 导航没有传递到标题右键?
- codenameone - 可以支持 CN1 的 StickyHeaders 吗?
- python - C# 中的 pandas .rolling().mean() 模拟
- visual-studio-code - vscode自动括号在某些情况下不起作用,我可以通过键盘快捷键写一些单词吗?
- python - 创建将输入 csv 文件加载到应用程序的模块 - dijkstra 算法
- javascript - 使用 Axios 解析包装类型数组