背景
假设我们有一堆评论的数据需要存储,通常来说数据库中是上面的扁平形式,而我们显示出来应该是树形结构。
于是就有了这里的内容,扁平结构和树形结构相互转换。
扁平转树状
如下,内容都在注释里:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 
 | const flatComments = [{ id: 1, content: 'A', parent: -1 },
 { id: 2, content: 'B', parent: -1 },
 { id: 3, content: 'C', parent: 1 },
 { id: 4, content: 'D', parent: 3 },
 { id: 5, content: 'E', parent: 2 },
 ]
 
 function toTree(arr) {
 const root = []
 
 
 arr = arr.map(item => ({ ...item }))
 
 
 const map = arr.reduce((pre, cur) => {
 pre[cur.id] = cur
 return pre
 }, {})
 
 
 map[-1] = { children: root }
 
 arr.forEach(item => {
 
 
 
 const children = map[item.parent].children ||= []
 children.push(item)
 })
 
 return root
 }
 
 console.log(toTree(flatComments))
 
 | 
读者可以打开控制台试一试,看看是否为预期效果。
树状转扁平
其实这个要简单得多,直接递归调用即可:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 
 | const treeComments = [{
 id: 1,
 content: 'A',
 children: [
 {
 id: 3,
 content: 'C',
 children: [{ id: 4, content: 'D', children: [] }]
 }
 ]
 },
 {
 id: 2,
 content: 'B',
 children: [{ id: 5, content: 'E', children: [] }]
 }
 ]
 
 function toFlat(tree) {
 const result = []
 
 
 const convert = ({ id, content, children }, parent) => {
 
 result.push({ id, content, parent })
 
 children.forEach(child => {
 convert(child, id)
 })
 }
 
 
 tree.forEach(root => {
 convert(root, -1)
 })
 
 return result
 }
 
 console.log(toFlat(treeComments))
 
 | 
读者可以打开控制台试一试,看看效果如何。
后记
如果要追求效率,不必像本文中一样拷贝原始数据,直接在原对象上修改即可。
不过考虑到诸多bug都是由于对象引用混乱造成的,所以在写代码的时候需要注意这一点。