![](/img/trans.png)
[英]How filter in a nested tree object without losing structure in javascript?
[英]Recursive tree search in a nested object structure in JavaScript
我試圖弄清楚如何在這個 JSON 對象中遞歸搜索節點。 我嘗試過一些東西但無法得到它:
var tree = {
"id": 1,
"label": "A",
"child": [
{
"id": 2,
"label": "B",
"child": [
{
"id": 5,
"label": "E",
"child": []
},
{
"id": 6,
"label": "F",
"child": []
},
{
"id": 7,
"label": "G",
"child": []
}
]
},
{
"id": 3,
"label": "C",
"child": []
},
{
"id": 4,
"label": "D",
"child": [
{
"id": 8,
"label": "H",
"child": []
},
{
"id": 9,
"label": "I",
"child": []
}
]
}
]
};
這是我的非工作解決方案,這可能是因為第一個節點只是一個值,而孩子在數組中:
function scan(id, tree) {
if(tree.id == id) {
return tree.label;
}
if(tree.child == 0) {
return
}
return scan(tree.child);
};
您的代碼只是缺少一個循環來檢查child
數組中節點的每個子節點。 如果標簽不存在於樹中,此遞歸函數將返回節點的label
屬性或undefined
:
const search = (tree, target) => { if (tree.id === target) { return tree.label; } for (const child of tree.child) { const found = search(child, target); if (found) { return found; } } }; const tree = {"id":1,"label":"A","child":[{"id":2,"label":"B","child":[{"id":5,"label":"E","child":[]},{"id":6,"label":"F","child":[]},{"id":7,"label":"G","child":[]}]},{"id":3,"label":"C","child":[]},{"id":4,"label":"D","child":[{"id":8,"label":"H","child":[]},{"id":9,"label":"I","child":[]}]}]}; console.log(search(tree, 1)); console.log(search(tree, 6)); console.log(search(tree, 99));
您還可以使用不會導致堆棧溢出的顯式堆棧迭代地執行此操作(但請注意,速記stack.push(...curr.child);
由於擴展語法可能會溢出某些 JS 引擎的參數大小,因此對大量子數組使用顯式循環或concat
):
const search = (tree, target) => { for (const stack = [tree]; stack.length;) { const curr = stack.pop(); if (curr.id === target) { return curr.label; } stack.push(...curr.child); } }; const tree = {"id":1,"label":"A","child":[{"id":2,"label":"B","child":[{"id":5,"label":"E","child":[]},{"id":6,"label":"F","child":[]},{"id":7,"label":"G","child":[]}]},{"id":3,"label":"C","child":[]},{"id":4,"label":"D","child":[{"id":8,"label":"H","child":[]},{"id":9,"label":"I","child":[]}]}]}; for (let i = 0; ++i < 12; console.log(search(tree, i)));
更通用的設計將返回節點本身,並讓調用者訪問.label
屬性(如果他們願意),或者以其他方式使用對象。
請注意,JSON 純粹是序列化(字符串化、原始)數據的字符串格式。 一旦您將 JSON 反序列化為 JavaScript 對象結構,就像這里一樣,它就不再是 JSON。
可以使用第三個參數遞歸寫入scan
該參數對要掃描的節點隊列進行建模
const scan = (id, tree = {}, queue = [ tree ]) =>
// if id matches node id, return node label
id === tree.id
? tree.label
// base case: queue is empty
// id was not found, return false
: queue.length === 0
? false
// inductive case: at least one node
// recur on next tree node, append node children to queue
: scan (id, queue[0], queue.slice(1).concat(queue[0].child))
因為 JavaScript 支持默認參數,所以scan
的調用點不變
console.log
( scan (1, tree) // "A"
, scan (3, tree) // "C"
, scan (9, tree) // "I"
, scan (99, tree) // false
)
在下面的瀏覽器中驗證它是否有效
const scan = (id, tree = {}, queue = [ tree ]) => id === tree.id ? tree.label : queue.length === 0 ? false : scan (id, queue[0], queue.slice(1).concat(queue[0].child)) const tree = { id: 1 , label: "A" , child: [ { id: 2 , label: "B" , child: [ { id: 5 , label: "E" , child: [] } , { id: 6 , label: "F" , child: [] } , { id: 7 , label: "G" , child: [] } ] } , { id: 3 , label: "C" , child: [] } , { id: 4 , label: "D" , child: [ { id: 8 , label: "H" , child: [] } , { id: 9 , label: "I" , child: [] } ] } ] } console.log ( scan (1, tree) // "A" , scan (3, tree) // "C" , scan (9, tree) // "I" , scan (99, tree) // false )
這是使用對象掃描的解決方案
// const objectScan = require('object-scan'); const tree = {"id":1,"label":"A","child":[{"id":2,"label":"B","child":[{"id":5,"label":"E","child":[]},{"id":6,"label":"F","child":[]},{"id":7,"label":"G","child":[]}]},{"id":3,"label":"C","child":[]},{"id":4,"label":"D","child":[{"id":8,"label":"H","child":[]},{"id":9,"label":"I","child":[]}]}]}; const search = (obj, id) => objectScan(['**.id'], { abort: true, filterFn: ({ value, parent, context }) => { if (value === id) { context.push(parent.label); return true; } return false; } })(obj, [])[0]; console.log(search(tree, 1)); // => A console.log(search(tree, 6)); // => F console.log(search(tree, 99)); // => undefined
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@13.7.1"></script>
免責聲明:我是對象掃描的作者
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.