我试图创建一个"树"查看我的数据库中的所有页面。要做到这一点,我已经给每一页"父母"属性以及它所属的页面的唯一ID。
现在我想以递归方式将这个对象数组嵌套在自身内部,以便所有子页面都嵌套在相应的父页面中。使用父标识作为参考,从以下方法转换以下数组的最有效方法是什么:
[
{
_id: 1,
title: 'Page A-1',
parent: null
},
{
_id: 2,
title: 'Page A-2',
parent: 1
},
{
_id: 3,
title: 'Page A-3',
parent: 2
},
{
_id: 4,
title: 'Page A-4',
parent: 3
},
{
_id: 5,
title: 'Page A-5',
parent: 4
},
{
_id: 6,
title: 'Page B-1',
parent: null
},
{
_id: 7,
title: 'Page B-2',
parent: 6
},
{
_id: 8,
title: 'Page B-3',
parent: 7
},
{
_id: 9,
title: 'Page B-4',
parent: 8
},
{
_id: 10,
title: 'Page B-5',
parent: 8
},
{
_id: 11,
title: 'Page C-1',
parent: null
}
]
进入这个:
[
{
_id: 1,
title: 'Page A-1',
children: [
{
_id: 2,
title: 'Page A-2',
children: [
{
_id: 3,
title: 'Page A-3',
children: [
{
_id: 4,
title: 'Page A-4',
children: [
{
_id: 5,
title: 'Page A-5',
children: [
]
}
]
}
]
}
]
}
]
},
{
_id: 6,
title: 'Page B-1',
children: [
{
_id: 7,
title: 'Page B-2',
children: [
{
_id: 8,
title: 'Page B-3',
children: [
{
_id: 9,
title: 'Page B-4',
children: []
},
{
_id: 10,
title: 'Page B-5',
children: []
}
]
}
]
}
]
},
{
_id: 11,
title: 'Page C-1',
children: []
}
]
答案 0 :(得分:1)
在循环遍历数组时,我会查找所有对象,并在同一循环中将子项添加到父项。假设您的数据不是很大而且存在内存问题,您可以在一个循环中通过数组执行此操作,而无需在父树中搜索树。
[注意:这假设父项是在数组中的子项之前定义的。如果不是你,你将不得不在循环中做更多的工作(但不多)]
let data = [
{
_id: 1,
title: 'Page A-1',
parent: null
},
{
_id: 2,
title: 'Page A-2',
parent: 1
},
{
_id: 3,
title: 'Page A-3',
parent: 2
},
{
_id: 4,
title: 'Page A-4',
parent: 3
},
{
_id: 5,
title: 'Page A-5',
parent: 4
},
{
_id: 6,
title: 'Page B-1',
parent: null
},
{
_id: 7,
title: 'Page B-2',
parent: 6
},
{
_id: 8,
title: 'Page B-3',
parent: 7
},
{
_id: 9,
title: 'Page B-4',
parent: 8
},
{
_id: 10,
title: 'Page B-5',
parent: 8
},
{
_id: 11,
title: 'Page C-1',
parent: null
}
]
let lookup = {}
let tree = {}
data.forEach(item => {
let obj = {_id: item._id, title: item.title, children: [] }
// add to lookup
if(!lookup[item._id]) lookup[item._id] = obj
if(!item.parent) {
// a root node. Add directly to tree
tree[item._id] = obj
} else{
// a child node. Add to parent's children array
lookup[item.parent].children.push(obj)
}
})
console.log(tree)

答案 1 :(得分:1)
我的回答将忽略这样做的必要性,并在大O复杂性方面为您提供最强大的时间效率方法。
算法包含线性复杂度O(items.length)
的三个步骤,这使得整个算法也是线性的。
注意:由于常见的权衡,我牺牲空间来实现最佳时间复杂度。
步骤1):
遍历您的项目并构建Map<id, object>
:
// you can also use a POJO here
// i'm using a map to demonstrate the appropriate data structure
const map = items.reduce((map, item) => {
map.set(item._id, item);
// Note: it might be safer to not use original objects when building the tree
// and create new objects instead. See the comment in step 2 as well.
/*
map.set(item._id, {
...item,
children: []
})
*/
return map;
}, new Map())
步骤2)
遍历您的项目并将每个项目嵌套在其父项下。
items.forEach(item => {
if (item.parent) {
const parent = map.get(item.parent);
// Note: this will actually edit your original objects
// Since mutability is the cause of many bugs, if you can afford it
// I'd create new objects with the children property in step 1
// when inserting items into the map which would make this if
// statement redundant
if (!parent.children) {
parent.children = [];
}
parent.children.push(item);
}
})
步骤3)
迭代地图中的项目并选择顶级父母:
const result = [];
for (const item of map.values()) {
if (!item.parent) {
result.push(item);
}
}
以下是一个完整的例子:
const items=[{_id:1,title:"Page A-1",parent:null},{_id:2,title:"Page A-2",parent:1},{_id:3,title:"Page A-3",parent:2},{_id:4,title:"Page A-4",parent:3},{_id:5,title:"Page A-5",parent:4},{_id:6,title:"Page B-1",parent:null},{_id:7,title:"Page B-2",parent:6},{_id:8,title:"Page B-3",parent:7},{_id:9,title:"Page B-4",parent:8},{_id:10,title:"Page B-5",parent:8},{_id:11,title:"Page C-1",parent:null}];
// step 1
const map = items.reduce((map, item) => {
map.set(item._id, item);
return map;
}, new Map())
// step 2
items.forEach(item => {
if (item.parent) {
const parent = map.get(item.parent);
if (!parent.children) {
parent.children = [];
}
parent.children.push(item);
}
})
// step 3
const result = [];
for (const item of map.values()) {
if (!item.parent) {
result.push(item);
}
}
console.log(result);
&#13;
在现实世界中,性能不仅取决于算法的复杂性,还取决于所使用的所有操作和数据结构的实际实现细节。如果这种关键性能对您很重要,那么构建最佳算法需要进行实际的基准测试。