![](/img/trans.png)
[英]How to convert flat data structure to tree structure in JavaScript using recursion
[英]convert a flat json file to tree structure in javascript
我基本上是試圖將平面json文件轉換為樹視圖。 在這里,樹視圖所需的父子關系由使用源和目標的鏈接鍵來維護。
這是示例原始輸入:
{
"nodes" : [
{
name: "bz_db",
index: 0
},
{
name: "mysql",
index: 1
},
{
name: "postgres",
index: 2
},
{
name: "it-infra",
index: 3
},
{
name: "user-count",
index: 4
}
],
links: [
{
source: 0, target: 1
},
{
source: 0, target: 3
},
{
source: 1, target: 3
},
{
source: 3, target: 4
}
]
}
如您所見,鏈接字段保持了這種關系,最后我希望我的數據采用以下格式:
{
name: "bz_db",
children: [
{
name: "mysql",
children: [
{
name: "it-infra",
children: [
{
name: "user_count",
children: []
}
]
}
]
},
{
name: "it-infra",
children: [{
name: "user_count",
children: []
}
]
}
]
}
我試圖解決此問題,但它只適用於1級(以顯示所選根元素的直接子級)。
var findObjectByKeyValue = function(arrayOfObject, key, value){
return _.find(arrayOfObject, function(o){ return o[key] == value})
}
var rootObject = findObjectByKeyValue(sample_raw_input.nodes, 'name', 'bz_db');
var treeObject = {
name: rootObject.name,
index: rootObject.index,
root: true,
children: []
};
angular.forEach(dependencyData.links, function(eachLink){
if(treeObject.index == eachLink.source){
var rawChildObject = findObjectByKeyValue(dependencyData.nodes, 'index', eachLink.target);
var childObject = {};
childObject.index = rawChildObject.index;
childObject.name = rawChildObject.name;
childObject.children = [];
treeObject.children.push(childObject);
}
});
但是上面的代碼只返回第一層依賴關系,但是我想要層次關系。 我知道我可以在這里使用遞歸。 但是我對此不太滿意。
Josh的答案使用了一系列map
> filter
> map
> find
調用,每個調用都通過一組數據進行迭代。 隨着集合中節點數量的增加,這種循環的循環會導致驚人的計算復雜性。
您可以通過在每個nodes
和links
上使用一次reduce
來大大簡化樹的創建。 與Array需要線性時間(較慢)的find
相比, Map
還可以以對數時間執行查找。 當您考慮為輸入的每個元素調用此操作時,很明顯會看到時間上的顯着差異。
const makeTree = (nodes = [], links = []) =>
links.reduce
( (t, l) =>
t.set ( l.source
, MutableNode.push ( t.get (l.source)
, t.get (l.target)
)
)
, nodes.reduce
( (t, n) => t.set (n.index, MutableNode (n.name))
, new Map
)
)
.get (0)
最后,我們提供了我們依賴的MutableNode
接口
const MutableNode = (name, children = []) =>
({ name, children })
MutableNode.push = (node, child) =>
(node.children.push (child), node)
以下是完整的程序演示。 JSON.stringify
僅用於顯示結果
const MutableNode = (name, children = []) => ({ name, children }) MutableNode.push = (node, child) => (node.children.push (child), node) const makeTree = (nodes = [], links = []) => links.reduce ( (t, l) => t.set ( l.source , MutableNode.push ( t.get (l.source) , t.get (l.target) ) ) , nodes.reduce ( (t, n) => t.set (n.index, MutableNode (n.name)) , new Map ) ) .get (0) const data = { nodes: [ { name: "bz_db", index: 0 } , { name: "mysql", index: 1 } , { name: "postgres", index: 2 } , { name: "it-infra", index: 3 } , { name: "user-count", index: 4 } ] , links: [ { source: 0, target: 1 } , { source: 0, target: 3 } , { source: 1, target: 3 } , { source: 3, target: 4 } ] } const tree = makeTree (data.nodes, data.links) console.log (JSON.stringify (tree, null, 2))
您可以依靠跟蹤對象引用,而無需任何遞歸。 使用Object.assign
,將節點列表映射到其子節點:
// Assuming that input is in `input`
const nodes = input.nodes.reduce((a, node) => {
a[node.index] = { ...node, index: undefined };
return a;
}, []);
// organize the links by their source
const links = input.links.reduce((a, link) => {
return a.set((a.get(link.source) || []).concat(nodes[link.target]);
}, new Map());
// Apply side effect of updating node children
nodes.forEach(node => Object.assign(node, {
children: links.get(node.index),
}));
因此,我獲取了節點列表,並為每個節點分配了一個新數組(以改變節點本身,請記住,這是一個副作用)。 這些children
節點是鏈接此節點的所有鏈接,我們Array#map
將它們轉換為target
ID到所需的實際節點。
只是分享樣本,與您的樣本略有不同。 但這給您遞歸函數的提示。
function getNestedChildren(arr, parent) {
var out = []
for(var i in arr) {
if(arr[i].parent == parent) {
var children = getNestedChildren(arr, arr[i].id)
if(children.length) {
arr[i].children = children
}
out.push(arr[i])
}
}
return out
}
var flat = [
{id: 1, title: 'hello', parent: 0},
{id: 2, title: 'hello', parent: 0},
{id: 3, title: 'hello', parent: 1},
{id: 4, title: 'hello', parent: 3},
{id: 5, title: 'hello', parent: 4},
{id: 6, title: 'hello', parent: 4},
{id: 7, title: 'hello', parent: 3},
{id: 8, title: 'hello', parent: 2}
]
var nested = getNestedChildren(flat, 0)
console.log(nested)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.