我有一个以下形式的树对象:
nav[role="top"] li:not(.active) a:hover {
height:1px;
text-decoration: none;
width: 70px;
background-color: #aecacc;
color:#fff;
}
我试图返回给定数组[0,0,0]的路径的子树,该路径将返回var data = [{
"root": true,
"label": null,
"question": "What product category?",
"nodes": [{
"label": "Clothes",
"question": "What type of clothing?",
"nodes": [{
"label": "Jeans",
"question": "Color of jeans?",
"nodes": [{
"label": "Blue",
"question": null,
"nodes": null
},
]
}]
}]
}];
。我正在尝试一种迭代方法,是否有可能以递归方式进行?
答案 0 :(得分:4)
这是递归函数:
function subTree(arr, indexes) {
var a = arr[indexes[0]];
return indexes.length > 1 ? subTree(a.nodes, indexes.slice(1)) : a;
}
var data = [{
"root": true,
"label": null,
"question": "What product category?",
"nodes": [{
"label": "Clothes",
"question": "What type of clothing?",
"nodes": [{
"label": "Jeans",
"question": "Color of jeans?",
"nodes": [{
"label": "Blue",
"question": null,
"nodes": null
}]
}]
}]
}];
console.log(subTree(data, [0,0,0]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
正如您在评论中提出的问题,这是我在解决这个问题时所经历的过程:
我想到的第一件事:我可能需要通过对象属性来找到有孩子的那个。
第二件事:不,我没有 - 它总是nodes
属性。
然后:但是等待 - 第一个索引不是来自nodes
属性,而是所有其他索引。获得通用解决方案是一个问题吗?
然后,我意识到它不是,因为第一次调用以数组开始 - 我不需要知道它是一个作为nodes
属性的值给出的数组还是只是初始数据数组。数组是一个数组。只有在第一次递归调用时(以及所有更深层次的调用),我才需要按名称提及nodes
属性,并且它始终是该属性名称。
似乎合乎逻辑的是,在每次递归时,您都会传递nodes
属性的数组和剩余索引的数组,因此没有已经处理过的索引。后一个数组将减少为一个空数组,这将是递归的终点。
然后我开始编写代码来处理递归结束的情况,即你没有索引的地方。首先我想写
function subTree(arr, indexes) {
if (!indexes.length) return arr;
// ...
}
但这不对,因为返回值不应该是一个数组,而是具有该数组的对象 - 所以实际上这个代码会被递归得太深了!
所以第二次尝试成了:
function subTree(arr, indexes) {
var index = indexes.shift();
if (indexes.length == 0) return arr[index];
// ...
}
shift
调用似乎是删除第一个索引并将其保存在单独变量中的好方法,因此它可以用于返回正确的对象。
这看起来很好:如果调用是subTree(data, [0])
,我的确会得到理想的结果。
然后我继续编写递归案例:
function subTree(arr, indexes) {
var index = indexes.shift();
if (indexes.length == 0) return arr[index];
return subTree(arr[index].nodes, indexes);
}
这看起来也很好。它奏效了。
但是看到两个由return
分隔的if
语句需要三元运算符,所以我将其更改为:
function subTree(arr, indexes) {
var index = indexes.shift();
return indexes.length ? subTree(arr[index].nodes, indexes) : arr[index];
}
我发布了这个,然后意识到使用shift
不是一个好主意:它修改了传递给函数的参数,这对调用者来说不是很好:它是一个意想不到的副作用。所以我应该创建新的数组实例,而不是修改给定的索引数组:
function subTree(arr, indexes) {
var index = indexes[0];
return indexes.length > 1 ? subTree(arr[index].nodes, indexes.slice(1)) : arr[index];
}
slice
是一个获取给定数组的一部分的浅表副本的方法,因此仅使用1
参数创建一个新数组,它不再具有第一个索引。通过这种工作方式,条件当然可以从简单的indexes.length
更改为indexes.length > 1
。
最后,我觉得有点愚蠢,我创建了一个变量index
,避免重复[0]
,但没有避免两次使用arr[index]
。那么最后的解决方案就浮出水面了。
希望这有帮助。