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

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

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 及自身记录到字典中,对执行效率进行了优化

相关文章
|
7月前
|
设计模式 算法 Java
【数据结构和算法】找到最高海拔
这是力扣的 1732 题,难度为简单,解题方案有很多种,本文讲解我认为最奇妙的一种。这是一道非常经典的前缀和问题,虽然看似简单,但它却能让你深入理解前缀和的特点。有一个自行车手打算进行一场公路骑行,这条路线总共由n + 1个不同海拔的点组成。自行车手从海拔为0的点0开始骑行。 给你一个长度为n的整数数组gain,其中gain[i]是点i和点i + 1的净海拔高度差(0
118 1
|
7月前
|
存储 算法
算法编程(二十六):判断路径是否相交
算法编程(二十六):判断路径是否相交
62 0
|
存储 算法
【每日挠头算法题(6)】二叉树的所有路径|神奇字符串
【每日挠头算法题(6)】二叉树的所有路径|神奇字符串
|
4月前
|
存储 C语言
【C深度解剖】计算机数据下载和删除原理
【C深度解剖】计算机数据下载和删除原理
|
7月前
leetcode代码记录(下一个更大元素 II
leetcode代码记录(下一个更大元素 II
27 0
|
7月前
|
索引
leetcode代码记录(下一个更大元素 I
leetcode代码记录(下一个更大元素 I
25 0
算法训练Day18|● 110.平衡二叉树 ● 257. 二叉树的所有路径 ● 404.左叶子之和
算法训练Day18|● 110.平衡二叉树 ● 257. 二叉树的所有路径 ● 404.左叶子之和
复杂数据的几种遍历方式(有点绕)
复杂数据的几种遍历方式(有点绕)
63 0
重生之我是孔乙己——查找数组缺失元素的几种方法
重生之我是孔乙己——查找数组缺失元素的几种方法
83 0
|
算法
删除链表中间节点(变形题目,简单难度)
删除链表中间节点(变形题目,简单难度)
92 1
删除链表中间节点(变形题目,简单难度)