有時我們需要從扁平的陣列結構(flat array),根據id,和pid構建出樹形陣列結構(tree array),這種情形經常出現在巢狀的目錄結構,如下圖:
或者企業的部門架構,也會出現上面的類似結構。
類似上面的情景,假如我們有以下的資料:
let entries = [{
"id": "12",
"parentId": "0",
"text": "Man",
"level": "1",
"children": null
},
{
"id": "7",
"parentId": "12",
"text": "Other",
"level": "2",
"children": null
},
{
"id": "8",
"parentId": "7",
"text": "Bird",
"level": "3",
"children": null
},
{
"id": "9",
"parentId": "0",
"text": "Woman",
"level": "1",
"children": null
},
{
"id": "11",
"parentId": "9",
"text": "Girl",
"level": "2",
"children": null
}
];
我們期待通過一個演算法,構建出下面的結構:
[
{
"id": "12",
"parentId": "0",
"text": "Man",
"level": "1",
"children": [
{
"id": "7",
"parentId": "12",
"text": "Other",
"level": "2",
"children": [
{
"id": "8",
"parentId": "7",
"text": "Bird",
"level": "3",
"children": []
}
]
}
]
},
{
"id": "9",
"parentId": "0",
"text": "Woman",
"level": "1",
"children": [
{
"id": "11",
"parentId": "9",
"text": "Girl",
"level": "2",
"children": []
}
]
}
]
也許我們可以想到,在遍歷陣列的時候使用遞迴。沒錯可以解決問題,但是這種方式並不高效。
最近,在Stack Overflow上看到一個方法,感覺不錯,貼出來分享一下:
function list_to_tree(list) {
var map = {}, node, roots = [], i;
for (i = 0; i < list.length; i += 1) {
map[list[i].id] = i; // initialize the map
list[i].children = []; // initialize the children
}
for (i = 0; i < list.length; i += 1) {
node = list[i];
if (node.parentId !== "0") {
// if you have dangling branches check that map[node.parentId] exists
list[map[node.parentId]].children.push(node);
} else {
roots.push(node);
}
}
return roots;
}
演算法的複雜度是Θ(n log(n))。
如果使用遞迴,那麼複雜度是Θ(n^2)。如果資料集比較大,那麼執行的時間會很長。