将数组还原为树的各种姿势

简介: 将数组还原为树的各种姿势

a1355abfbc23d339cdde402bd5b143e.png

前言

工作中面对将数组还原为树的需求应该说是相当常见,例如功能菜单,部门组织等等,都有类似的功能,需要前端将后端传递过来的扁平数组还原成带有层级关系的组织树,那么具体有哪些实现方法呢,今天就和大家一起来探讨探讨

问题分析

通过 idpid 来关联数据,应该是我们工作中最常用的方案之一,存储模型如下

id pid data
1 0 a
2 1 b
3 1 c

该模型代表了如下的树状结构

{
    id: 1,
    pid: 0,
    data: 'a',
    children: [
        {id: 2, pid: 1, data: 'b'},
        {id: 3, pid: 1, data: 'c'},
    ]
}
复制代码

今天就以这种数据结构为例,来编写我们数组转树的方法

数组转树

const list = [
  { pid: null, id: 1, data: "1" },
  { pid: 1, id: 2, data: "2-1" },
  { pid: 1, id: 3, data: "2-2" },
  { pid: 2, id: 4, data: "3-1" },
  { pid: 3, id: 5, data: "3-2" },
  { pid: 4, id: 6, data: "4-1" },
]
复制代码

递归

讲递归前顺便过一下数组中的 reduce 方法,对处理类似问题的结果时非常好用,可以让我们逐项处理数据时得到一个叠加的结果

reduce() 方法接收一个函数作为累加器,reduce 为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素

callback: 函数中主要用到的2个参数

  • previousValue (上一次计算的结果或初始值)
  • currentValue (当前的项)

例如我们简单的把数组的每一项都放在一个 tree 里边

const tree = list.reduce((res, item)=> {
    res.push(item)
    return res
}, [])
console.log(tree);
复制代码

本题使用递归时,需要明确我们递归过程得到返回值是一个数组,而最终结果是一个层级嵌套的数组,终止条件是循环遍历完每一项

function listToTree(list, pid) {
    const node = list.reduce((res, item) => {
        if (item.pid === pid) {
            // 匹配到该项进入下一层递归
            const children = listToTree(list, item.id)
            item.children = children
            // 如果匹配到,返回上次结果 + 匹配项
            return [...res, item]
        }
        // 如果没匹配到,返回上次结果
        return res
    }, [])
    return node
}
console.log(listToTree(list, null))
复制代码

迭代

运用迭代同样需要做循环遍历,只是这里我们会利用 js 对象是一个引用类型的特点,通过直接修改对象的属性,来最终确认层级关系

function listToTree(list, pid) {
    const map = {}
    const tree = []
    list.forEach(item => {
        map[item.id] = item
        item.children = []
    })
    list.forEach(item => {
        if (item.pid === pid) {
            // 只添加根元素,其余通过映射关系关联
            tree.push(item)
        } else {
            // 通过映射关系维护层级关系
            map[item.pid].children.push(item)
        }
    })
    return tree
}
console.log(listToTree(list, null))
复制代码

这里使用了用 map 空间换时间,用于将所有项的 id 及自身记录到字典中,对执行效率进行了优化

相关文章
|
8月前
|
存储 算法
算法编程(二十六):判断路径是否相交
算法编程(二十六):判断路径是否相交
73 0
|
8月前
平衡二叉树的插入和删除(从现在开始摆脱旋转)
平衡二叉树的插入和删除(从现在开始摆脱旋转)
83 9
|
算法
删除链表中间节点(变形题目,简单难度)
删除链表中间节点(变形题目,简单难度)
97 1
删除链表中间节点(变形题目,简单难度)
|
存储
数据结构上机实践第四周项目1 - 建立单链表
数据结构上机实践第四周项目1 - 建立单链表
数据结构上机实践第四周项目1 - 建立单链表
|
算法
数据结构上机实践第四周项目2 - 建设“单链表”算法库
数据结构上机实践第四周项目2 - 建设“单链表”算法库
106 0
数据结构上机实践第四周项目2 - 建设“单链表”算法库
|
算法 C++
数据结构上机实践第四周项目4 - 建设双链表算法库
数据结构上机实践第四周项目4 - 建设双链表算法库
137 0
数据结构上机实践第四周项目4 - 建设双链表算法库
|
算法
数据结构上机实践第14周项目2 - 二叉树排序树中查找的路径
数据结构上机实践第14周项目2 - 二叉树排序树中查找的路径
103 0
数据结构上机实践第14周项目2 - 二叉树排序树中查找的路径
|
算法
数据结构上机实践第四周项目3 - 单链表应用
数据结构上机实践第四周项目3 - 单链表应用
118 0
数据结构上机实践第四周项目3 - 单链表应用

热门文章

最新文章