Javascript 嵌套递归对象循环
我有对象数组,它们也可以有自己的数组。我的主要目标是在整个树中找到一个具有给定id的对象,并通过显示该对象所在位置的对象名来获取该元素的readmap 例如,我有这样的数据对象:Javascript 嵌套递归对象循环,javascript,arrays,loops,object,recursion,Javascript,Arrays,Loops,Object,Recursion,我有对象数组,它们也可以有自己的数组。我的主要目标是在整个树中找到一个具有给定id的对象,并通过显示该对象所在位置的对象名来获取该元素的readmap 例如,我有这样的数据对象: { id: '0', name: "Boys" children: [ { name: "Soldiers", children: [ { name: "Bravo" children:
{
id: '0',
name: "Boys"
children: [
{
name: "Soldiers",
children: [
{
name: "Bravo"
children: [
{name: "Tom"},
{name: "Andrew"}
]
}
]
},
{
name: "Runners",
children: [
{
name: "Team B"
children: [
{name: "Mark"},
{name: "David"}
]
}
]
}
]
}
我当前正在通过函数查找项
function findByName (name, array) {
for (const node of array) {
if (node.name === name) return node;
if (node.children) {
const child = findByName(name, node.children);
if (child) return child;
}
}
}
但要实现我的目标,我还需要实现这一价值的路线图。比如说
当我想找到
“Tom”
时。除了findByName
的结果外,我还想得到{name:“Tom”,road:[“Boys”,“soldies”,“Bravo”]
您需要传递另一个处理路径的属性。首先将路径定义为空数组。由于您只关心名称,因此每次找到具有子节点的节点时,都可以将该名称推入该数组
然后继续将更新后的数组传递给递归函数。请参见下面的工作示例:
(我更新了函数以返回一个包含结果和路径的对象)
演示:
您需要传递另一个处理路径的属性。首先将路径定义为空数组。由于您只关心名称,因此每次找到具有子节点的节点时,都可以将该名称推入该数组 然后继续将更新后的数组传递给递归函数。请参见下面的工作示例: (我更新了函数以返回一个包含结果和路径的对象) 演示:
您可以为调用函数中的每个级别添加路径,而无需移交路径
const
findByName=(数组,名称)=>{
for(数组的常量节点){
如果(node.name==name)返回{…节点,路径:[]};
if(节点子节点){
const child=findByName(node.children,name);
if(child)返回{…child,path:[node.name,…child.path]};
}
}
},
数据=[{id:'0',姓名:“男孩”,儿童:[{name:'soldies],儿童:[{name:'Bravo],儿童:[{name:'Tom},{name:'Andrew}]},{name:'Runners],儿童:[{name:'Team B],儿童:[{name:'Mark},{name:'David}]}]}];
log(findByName(数据'Tom'));
.as console wrapper{max height:100%!important;top:0;}
您可以为调用函数中的每个级别添加路径,而无需移交路径
const
findByName=(数组,名称)=>{
for(数组的常量节点){
如果(node.name==name)返回{…节点,路径:[]};
if(节点子节点){
const child=findByName(node.children,name);
if(child)返回{…child,path:[node.name,…child.path]};
}
}
},
数据=[{id:'0',姓名:“男孩”,儿童:[{name:'soldies],儿童:[{name:'Bravo],儿童:[{name:'Tom},{name:'Andrew}]},{name:'Runners],儿童:[{name:'Team B],儿童:[{name:'Mark},{name:'David}]}]}];
log(findByName(数据'Tom'));
.as控制台包装{最大高度:100%!重要;顶部:0;}
我喜欢这种类型或问题的生成器,因为它允许您选择一个、多个或所有结果。此外,生成器向调用者提供控制,允许您在对结果满意时停止搜索。这可以通过单个函数实现-
function*select(a=[],query=Boolean,path=[])
{for(常数a)
{if(query(t))产生{…t,path}
yield*select(t.children,query,[…path,t.name])
}
}
常量数据=
[{id:'0',name:'Boys],children:[{name:'soldies],children:[{name:'Bravo],children:[{name:'Tom},{name:'Andrew}]},{name:'Runners],children:[{name:'B队],children:[{name:'Mark},{name:'David}]}]}]
//选择“汤姆”或“马克”
for(select的常数(数据,v=>v.name='Tom'| | v.name=='Mark'))
console.log(“找到:”,r)
我喜欢这种类型或问题的生成器,因为它允许您选择一个、多个或所有结果。此外,生成器向调用者提供控制,允许您在对结果满意时停止搜索。这可以通过单个函数实现-
function*select(a=[],query=Boolean,path=[])
{for(常数a)
{if(query(t))产生{…t,path}
yield*select(t.children,query,[…path,t.name])
}
}
常量数据=
[{id:'0',name:'Boys],children:[{name:'soldies],children:[{name:'Bravo],children:[{name:'Tom},{name:'Andrew}]},{name:'Runners],children:[{name:'B队],children:[{name:'Mark},{name:'David}]}]}]
//选择“汤姆”或“马克”
for(select的常数(数据,v=>v.name='Tom'| | v.name=='Mark'))
console.log(“找到:”,r)
重新打开。具有不同的结构,子体作为对象属性,而不是子体作为对象属性。重新打开。具有不同的结构,子体作为对象属性,而不是子体作为对象属性。我知道有很好的理由重新打开它!我写了几个不同的答案,没有一个是h似乎提供了任何很棒的东西,所以我没有发布它们。我完全不奇怪你给出了一个优雅的答案!一个诡辩:我的名字find
与Array.prototype.find
及其短路返回。类似select
、query
或match
的东西击中了我我更清楚。我特别喜欢select
。我很高兴能做出有价值的贡献^ ^我也喜欢select
,现在更新答案。我知道有一个很好的理由重新打开这个!我写了几个不同的答案,没有一个看起来很好,所以我没有发布它们。我真的很高兴
function findByName(name, array, path = []) {
for (const node of array) {
if (node.name === name) return {result: node, path};
if (node.children) {
path.push(node.name) // We update the path with the current node name that has children
const child = findByName(name, node.children, path );
if (child) return { result: child, path};
}
}
}