简体   繁体   English

如何将具有父子关系的嵌套数组转换为普通数组?

[英]How to convert a nested array with parent child relationship to a plain array?

I have an array with nested objects having parent-child relationship like so:我有一个嵌套对象的数组,它们具有如下父子关系:

[
{id: 1, title: 'hello', parent: 0, children: [
    {id: 3, title: 'hello', parent: 1, children: [
        {id: 4, title: 'hello', parent: 3, children: [
            {id: 5, title: 'hello', parent: 4, children: []},
            {id: 6, title: 'hello', parent: 4, children: []}
        ]},
        {id: 7, title: 'hello', parent: 3, children: []}
    ]}
]},
{id: 2, title: 'hello', parent: 0, children: [
    {id: 8, title: 'hello', parent: 2, children: []}
]}
]

I need to convert it into a plain array retaining the parent child relationship like so and in the order of parent and all its children returned first before proceeding on to the next parent.我需要将其转换为保留父子关系的普通数组,并且按照父子的顺序及其所有子节点首先返回,然后再继续下一个父节点。

[
{id: 1, 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: 2, title: 'hello', parent: 0},
{id: 8, title: 'hello', parent: 2}
]

I was able to convert the other way round with a recursive function.我能够使用递归 function 进行相反的转换。

But I need to do the opposite in an efficient way.但我需要以一种有效的方式做相反的事情。 There is multilevel nesting as shown in the sample nested array.如示例嵌套数组所示,存在多级嵌套。

EDIT: Updated the nested array to have an empty children array for leaf nodes.编辑:将嵌套数组更新为叶节点有一个空的子数组。

And also, an answer in ES5 would help.而且,ES5 中的答案会有所帮助。

I just use a simple recursive function to make an array object into a plain array我只是使用简单的递归 function 将数组 object 制作成普通数组

 var arr = [ {id: 1, title: 'hello', parent: 0, children: [ {id: 3, title: 'hello', parent: 1, children: [ {id: 4, title: 'hello', parent: 3, children: [ {id: 5, title: 'hello', parent: 4, children: []}, {id: 6, title: 'hello', parent: 4, children: []} ]}, {id: 7, title: 'hello', parent: 3, children: []} ]} ]}, {id: 2, title: 'hello', parent: 0, children: [ {id: 8, title: 'hello', parent: 2, children: []} ]} ]; var result = []; var convertArrToObj = (arr) => { arr.forEach(e => { if (e.children) { result.push({ id: e.id, title: e.title, parent: e.parent }); convertArrToObj(e.children); } else result.push(e); }); }; convertArrToObj(arr); console.log(result);

In ES5 you can also use some functional programming approach, and flatten an array with [].concat.apply :在 ES5 中,您还可以使用一些函数式编程方法,并使用[].concat.apply展平数组:

 function flatten(arr) { return [].concat.apply([], arr.map(function (obj) { return [].concat.apply([ { id: obj.id, title: obj.title, parent: obj.parent } ], flatten(obj.children)); })); } let arr = [{id: 1, title: 'hello', parent: 0, children: [{id: 3, title: 'hello', parent: 1, children: [{id: 4, title: 'hello', parent: 3, children: [{id: 5, title: 'hello', parent: 4, children: []},{id: 6, title: 'hello', parent: 4, children: []}]},{id: 7, title: 'hello', parent: 3, children: []}]}]},{id: 2, title: 'hello', parent: 0, children: [{id: 8, title: 'hello', parent: 2, children: []}]}]; console.log(flatten(arr));

In ES6 the same algorithm reduces to the following:在 ES6 中,相同的算法简化为以下内容:

 const flatten = arr => arr.flatMap(({children, ...o}) => [o, ...flatten(children)]); let arr = [{id: 1, title: 'hello', parent: 0, children: [{id: 3, title: 'hello', parent: 1, children: [{id: 4, title: 'hello', parent: 3, children: [{id: 5, title: 'hello', parent: 4, children: []},{id: 6, title: 'hello', parent: 4, children: []}]},{id: 7, title: 'hello', parent: 3, children: []}]}]},{id: 2, title: 'hello', parent: 0, children: [{id: 8, title: 'hello', parent: 2, children: []}]}]; console.log(flatten(arr));

Using ES5 would require a lot more lines of code and like you said is not very efficient.使用 ES5 需要更多的代码行,就像你说的那样效率不高。

Here's my ES5 version, you should be able to notice the difference in performance这是我的 ES5 版本,你应该能注意到性能上的差异

 const data = [{id:1,title:'hello',parent:0,children:[{id:3,title:'hello',parent:1,children:[{id:4,title:'hello',parent:3,children:[{id:5,title:'hello',parent:4,children:[]},{id:6,title:'hello',parent:4,children:[]}]},{id:7,title:'hello',parent:3,children:[]}]}]},{id:2,title:'hello',parent:0,children:[{id:8,title:'hello',parent:2,children:[]}]}]; // Recursively function reduceArrayDimension(array) { var level = []; array.forEach(function(item) { level.push({ id: item.id, title: item.title, parent: item.parent }); item.children.forEach(function(child) { reduceArrayDimension([child]).forEach(function(childItem) { level.push(childItem); }); }); }); return level; } console.log(reduceArrayDimension(data));

And ES6和 ES6

 const data=[{id:1,title:'hello',parent:0,children:[{id:3,title:'hello',parent:1,children:[{id:4,title:'hello',parent:3,children:[{id:5,title:'hello',parent:4,children:[]},{id:6,title:'hello',parent:4,children:[]}]},{id:7,title:'hello',parent:3,children:[]}]}]},{id:2,title:'hello',parent:0,children:[{id:8,title:'hello',parent:2,children:[]}]}]; // Recursively function reduceArrayDimension(array) { const level = []; array.forEach(item => { level.push({id: item.id, title: item.title, parent: item.parent}); if (item.children) level.push(...reduceArrayDimension(item.children)); }); return level; } console.log(reduceArrayDimension(data));

If the data is not very large, this could be a pragmatic method如果数据不是很大,这可能是一种务实的方法

 const data = [{ id: 1, title: 'hello', parent: 0, children: [{ id: 3, title: 'hello', parent: 1, children: [{ id: 4, title: 'hello', parent: 3, children: [{ id: 5, title: 'hello', parent: 4 }, { id: 6, title: 'hello', parent: 4, children:[]} ] }, { id: 7, title: 'hello', parent: 3 } ] }] }, { id: 2, title: 'hello', parent: 0, children: [{ id: 8, title: 'hello', parent: 2 }] } ]; const str = JSON.stringify(data).replaceAll('"children":[',"},").replaceAll("]}","").replaceAll(",,",",") // handle empty children.replaceAll(",}","}"); console.log(JSON.parse(str).sort((a,b) => a.id-b.id))

if data is large can consider use tail optimization and async/await如果数据很大可以考虑使用尾部优化和异步/等待

 const arr = [ {id: 1, title: 'hello', parent: 0, children: [ {id: 3, title: 'hello', parent: 1, children: [ {id: 4, title: 'hello', parent: 3, children: [ {id: 5, title: 'hello', parent: 4}, {id: 6, title: 'hello', parent: 4} ]}, {id: 7, title: 'hello', parent: 3} ]} ]}, {id: 2, title: 'hello', parent: 0, children: [ {id: 8, title: 'hello', parent: 2} ]} ]; const convertArr = (arr) => { return arr.reduce((init, cur) => { const plain = init.concat(cur); const children = cur.children; return plain.concat(children && children.length? convertArr(children): []) }, []) } const generateArr = (arr) => { return convertArr(arr).map(v => ({ id: v.id, parent: v.parent, title: v.title })) } console.log('result:', generateArr(arr))

You can use a generator function:您可以使用生成器 function:

 var arr = [ {id: 1, title: 'hello', parent: 0, children: [ {id: 3, title: 'hello', parent: 1, children: [ {id: 4, title: 'hello', parent: 3, children: [ {id: 5, title: 'hello', parent: 4, children: []}, {id: 6, title: 'hello', parent: 4, children: []} ]}, {id: 7, title: 'hello', parent: 3, children: []} ]} ]}, {id: 2, title: 'hello', parent: 0, children: [ {id: 8, title: 'hello', parent: 2, children: []} ]} ]; function* flatten(d){ for (var i of d){ yield {id:i.id, title:i.title, parent:i.parent} yield* flatten(i.children) } } console.log([...flatten(arr)])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM