Javascript 在树数据结构中聚合包含对象数组的属性
我有一个如下的树结构(没有深度限制,一般不超过6个子级别)。每个节点都有一个Javascript 在树数据结构中聚合包含对象数组的属性,javascript,recursion,tree,Javascript,Recursion,Tree,我有一个如下的树结构(没有深度限制,一般不超过6个子级别)。每个节点都有一个workItems属性,即workItem对象的数组 我想在每个节点上聚合工作项,这样一个节点就包含了它自己的工作项和它的所有后代的工作项 以下结构示例中,节点id11将具有以下工作项: [{ id: 'wi2' }, { id: 'wi3' }, { id: 'wi4' }, { id: 'wi5' }] // aggregated from node `111` 节点1将绝对
workItems
属性,即workItem
对象的数组
我想在每个节点上聚合工作项
,这样一个节点就包含了它自己的工作项和它的所有后代的工作项
以下结构示例中,节点id11
将具有以下工作项:
[{ id: 'wi2' },
{ id: 'wi3' },
{ id: 'wi4' },
{ id: 'wi5' }] // aggregated from node `111`
节点1
将绝对拥有树的所有工作项
javascript
const traverse = (tree) => {
const stack = [ tree ]
while (stack.length) {
const curr = stack.pop()
// do something here, I guess
stack.push(...curr.children)
}
}
树结构
{
id: '1',
title: '1',
workItems: [
{ id: 'wi1' }
],
children: [
{
id: '11',
title: '11',
workItems: [
{ id: 'wi2' },
{ id: 'wi3' },
{ id: 'wi4' }
],
children: [
{
id: '111',
title: '111',
workItems: [
{ id: 'wi5' },
],
children: []
}
]
},
{
id: '12',
title: '12',
workItems: [
{ id: 'wi6' }
],
children: [
{
id: '121',
title: '121',
workItems: [
{ id: 'wi7' },
{ id: 'wi8' }
],
children: []
}
]
}
]
}
您可以进行深度优先搜索,并将
workItmes
的父数组交给pusihng嵌套项
const
getWorkItems=({workItems,children=[]})=>
(workItems.push(…children.flatMap(getWorkItems)),workItems);
变量树={id:'1',title:'1',工作项:[{id:'wi1'}],子项:[{id:'11',title:'11',工作项:[{id:'wi2'},{id:'wi3'},{id:'wi4'}],子项:[{id:'111',title:'111',工作项:[{id:'wi5'}],子项:[},{id:'12',工作项:[{id:'wi6'}],子项:[id:'121',title:'121',工作项:[{id:'wi7'},{id:'wi8'}],子项:[]}]};
getWorkItems(树);
console.log(树);
.as console wrapper{max height:100%!important;top:0;}
您可以进行深度优先搜索,并移交工作项的父数组
,以显示嵌套项
const
getWorkItems=({workItems,children=[]})=>
(workItems.push(…children.flatMap(getWorkItems)),workItems);
变量树={id:'1',title:'1',工作项:[{id:'wi1'}],子项:[{id:'11',title:'11',工作项:[{id:'wi2'},{id:'wi3'},{id:'wi4'}],子项:[{id:'111',title:'111',工作项:[{id:'wi5'}],子项:[},{id:'12',工作项:[{id:'wi6'}],子项:[id:'121',title:'121',工作项:[{id:'wi7'},{id:'wi8'}],子项:[]}]};
getWorkItems(树);
console.log(树);
.as console wrapper{max height:100%!important;top:0;}
这是一个创建新树而不是修改当前树的版本。(我非常喜欢不可变数据。)请注意,工作项仍然通过引用共享,包括在单个树内以及原始树和派生树之间
const addalldecents=(
{workItems,children=[],…rest},{,},
kids=children.map(addAllDecents)
) => ({
休息
workItems:[…workItems,…kids.flatMap(child=>child.workItems)],
孩子们:孩子们,
})
const tree={id:“1”,title:“1”,工作项:[{id:“wi1”},子项:[{id:“11”,title:“11”,工作项:[{id:“wi2”},{id:“wi3”},{id:“wi4”},子项:[{id:“111”,title:“111”,工作项:[{id:“wi5”},子项:[},{id:“12”,工作项:[{id:“wi6”},子项:[id:“121”,title:“wi8”{}],子项:[]}]};
log('New tree:',addAllDecents(tree))
console.log('原始树:',树)
.as console wrapper{max height:100%!important;top:0;}
这是一个创建新树而不是修改当前树的版本。(我非常喜欢不可变数据。)请注意,工作项仍然通过引用共享,包括在单个树内以及原始树和派生树之间
const addalldecents=(
{workItems,children=[],…rest},{,},
kids=children.map(addAllDecents)
) => ({
休息
workItems:[…workItems,…kids.flatMap(child=>child.workItems)],
孩子们:孩子们,
})
const tree={id:“1”,title:“1”,工作项:[{id:“wi1”},子项:[{id:“11”,title:“11”,工作项:[{id:“wi2”},{id:“wi3”},{id:“wi4”},子项:[{id:“111”,title:“111”,工作项:[{id:“wi5”},子项:[},{id:“12”,工作项:[{id:“wi6”},子项:[id:“121”,title:“wi8”{}],子项:[]}]};
log('New tree:',addAllDecents(tree))
console.log('原始树:',树)
。作为控制台包装器{max height:100%!important;top:0;}
树是对象(如示例)还是数组?有一种方法可以在不使用真正递归的情况下实现这一点。我将很快发布一个演示。为什么不使用递归?@NinaScholz,没有理由。我不太擅长这一点。研究您的解决方案很有启发性。树是对象吗(如示例所示)或者一个数组?有一种方法不需要真正的递归就可以实现。我很快会发布一个演示。为什么不使用递归?@NinaScholz,没有理由。我不是很擅长这一切。但是研究你的解决方案很有启发性。Scott,由于某些原因,我无法让它工作,我认为Nina的答案更容易一些。再次感谢你花时间讨论answer.Nina的答案当然更简单,而且和Nina的答案一样,非常好。我的设计是为了满足一个额外的限制:我不喜欢变异数据,而是创建新的结构。我不知道为什么它对你不起作用,但可能是你在一个没有flatMap
的环境中工作。如果是这样,我补充说斯科特,由于某种原因,我无法让它工作,我认为尼娜的答案更容易一些。再次感谢你花时间回答。尼娜的答案当然更容易,而且和尼娜的答案一样,非常好。我的答案是为了满足一个额外的限制:我更喜欢不改变数据,而不是创建数据新结构。我不知道为什么它不适合您,但可能是您在没有flatMap
的环境中工作。如果是这样,我又添加了一个版本来避免这种情况。如果数据结构是平面的,您的方法是什么:一个数组