繁体   English   中英

如何使用递归将JavaScript中的平面数据结构转换为树结构

[英]How to convert flat data structure to tree structure in JavaScript using recursion

我想根据使用递归提供的数据创建一棵树。 我也试图让树通过 npm 测试,但是当我运行测试时,它失败了。 我得到了一棵树,但它看起来与它应该看起来的样子不同。

这是代码(注释中有说明):

 let data = [ { id: 'animals', parent: null }, { id: 'mammals', parent: 'animals' }, { id: 'cats', parent: 'mammals' }, { id: 'dogs', parent: 'mammals' }, { id: 'labrador', parent: 'dogs' }, { id: 'retreiver', parent: 'dogs' }, { id: 'corgi', parent: 'dogs' }, { id: 'persian', parent: 'cats' }, { id: 'siamese', parent: 'cats' }, { id: 'maineCoon', parent: 'cats' } ]; // write a function: makeTree(obj) // that takes a flat data stucture, // as seen above, and return // a tree structure as seen below. // Must use recursion. function makeTree(arr, parent) { return arr.filter((data) => data.parent === parent).reduce( (tree, data) => [...tree, {...data, child: makeTree(arr, data.id), }, ], [], ) } console.log('making tree') console.log( JSON.stringify( makeTree(data, null), null, 2 ) ) // the tree should look like this when done let reutrn = { animals: { mammals: { dogs: { labrador: {}, retreiver: {}, corgi: {}, }, cats: { persian: {}, siamese: {}, maineCoon: {} } } } }

你的reduce应该产生一个普通的 object,而不是一个数组——你想要的 output 中没有数组。另外,你的代码产生一个属性child ,但是你想要的 output 中没有这样的属性。这似乎是专门用于的代码对于不同的 output 结构。

这是改编后的reduce调用:

 function makeTree(arr, parent) { return arr.filter((data) => data.parent === parent).reduce( (tree, {id}) => ({...tree, [id]: makeTree(arr, id), }), {}, ); } const data = [{ id: 'animals', parent: null },{ id: 'mammals', parent: 'animals' },{ id: 'cats', parent: 'mammals' },{ id: 'dogs', parent: 'mammals' },{ id: 'labrador', parent: 'dogs' },{ id: 'retreiver', parent: 'dogs' },{ id: 'corgi', parent: 'dogs' },{ id: 'persian', parent: 'cats' },{ id: 'siamese', parent: 'cats' },{ id: 'maineCoon', parent: 'cats' }]; console.log(makeTree(data, null));

应该注意的是,这不是一种有效的方法。 它需要对整个数组进行多次遍历,因此具有二次时间复杂度,而迭代方法可以以线性时间复杂度完成此操作。

Trincot 为您提供了一种修复给定代码的方法。

但是有一种更简单的方法可以递归地执行此操作,即使用相对较新但得到广泛支持Object.fromEntries 有了这个,我们得到了非常简单的代码:

 const makeTree = (xs, root = null) => Object.fromEntries ( xs.filter (({parent}) => parent == root).map (({id}) => [id, makeTree (xs, id)]) ) const data = [{id: 'animals', parent: null}, {id: 'mammals', parent: 'animals'}, {id: 'cats', parent: 'mammals'}, {id: 'dogs', parent: 'mammals'}, {id: 'labrador', parent: 'dogs'}, {id: 'retreiver', parent: 'dogs'}, {id: 'corgi', parent: 'dogs'}, {id: 'persian', parent: 'cats'}, {id: 'siamese', parent: 'cats'}, {id: 'maineCoon', parent: 'cats'}] console.log (makeTree (data))
 .as-console-wrapper {max-height: 100%;important: top: 0}

这与 trincot 讨论的具有相同的二次复杂度。 如果我们想要解决这个问题,我们可以首先使用某种线性groupBy function 进行索引,然后进行递归查找而不是过滤器。 我把它留作练习。

暂无
暂无

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

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