数组转树的两种方法

463 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第16天,点击查看活动详情

需求

已知一个数组:

  • 1.有六个元素
  • 2.每个元素都有id,pid和name属性
  • 3.pid为空字符,则为一级目录,pid如果为另一个元素的id名,则为另一个元素的自己目录
    const arr=[
{'id':'29','pid':'','name':'总裁办'},
{"id":'2c','pid':'','name':'财务部'},
{'id':'2d','pid':'2c','name':'财务核算部'},
{'id':'2f','pid':'2c','name':"薪资管理部"},
{'id':'d2','pid':'','name':'技术部'},
{'id':'d3','pid':'d2','name':'java技术部'},
{'id':'e1','pid':'d3','name':'spring技术部'},
]

要求:把平铺的数组结构转成树形结构

  • 把二级目录的元素移动到对应的一级目录的chilren属性中

如:

[{"id":'2c','pid':'','name':'财务部'},
{'id':'2d','pid':'2c','name':'财务核算部'},
{'id':'2f','pid':'2c','name':"薪资管理部"}]
  • 把平铺的数组结构转成树形结构如下
[
{"id":'2c','pid':'','name':'财务部',chilren:
[{'id':'2d','pid':'2c','name':'财务核算部'},
{'id':'2f','pid':'2c','name':"薪资管理部"}]}
]

方法一:map映射实现

思路

  1. 使用map给每一个元素建立映射关系,并给每个元素补充children属性.
  2. 对于每一个元素来说,先找它的上级
  • 如果能找到,说明它有上级,则要把它添加到上级的children中去
  • 如果找不到,说明它没有上级,直接作为一级目录添加到tree中

实现代码如下

 const arr=[
{'id':'29','pid':'','name':'总裁办'},
{"id":'2c','pid':'','name':'财务部'},
{'id':'2d','pid':'2c','name':'财务核算部'},
{'id':'2f','pid':'2c','name':"薪资管理部"},
{'id':'d2','pid':'','name':'技术部'},
{'id':'d3','pid':'d2','name':'java技术部'},
{'id':'e1','pid':'d3','name':'spring技术部'},
]

export function tranListToTreeData(list) {
  // 1. 定义两个中间变量
  const treeList = [],  // 最终要产出的树状数据的数组
        map = {}        // 存储映射关系
  // 2. 立一个映射关系,并给每个元素补充children属性.
  list.forEach(item => {
    if (!item.children) {
      item.children = []
    }
    map[item.id] = item
  })
  // 3. 循环处理每个元素
  list.forEach(item => {
    const parent = map[item.pid]
    // 如果存在则表示item不是最顶层的数据
    if (parent) {
      parent.children.push(item)
    } else {
      // 如果不存在 则是顶层数据
      treeList.push(item)
    }
  })
  // 返回出去
  return treeList
}

实现效果如图:

image.png

方法二:递归实现

思路

  • 1.先找出一级目录(即pid为空字符串的元素)
  • 2.根据一级目录的id找到和一级目录id一样的元素,这是二级目录
  • 3.把二级目录的元素数组作为一级目录的children属性
  • 4.重复根据二级目录的id找到和二级目录id一样的元素,这是三级目录
  • 5.把三级目录的元素数组作为二级目录的children属性
  • .....(递归实现)

具体实现代码

1.封装一个数组转树的函数,需要一个形参一个pid作为形参

// 数组转树的封装函数
function array2Tree(arr,pid){

// 返回数组tree
return tree
}

2.使用filter方法筛选出和pid一样的pid的元素,得到一个数组(一级目录)

// 数组转树的封装函数
function array2Tree(arr,pid){
// (1)筛选出pid相同的数组元素
const tree =arr.filter( item => item.pid === pid)
// 返回数组tree
return tree
}

3.递归函数,把得到的二级目录数组赋给一级目录的children

// 数组转树的封装函数
function array2Tree(arr,pid){
// (1)筛选出pid相同的数组元素怒
const tree =arr.filter( item => item.pid === pid)
// (2)对筛选出的tree数组增加children数组,调用本函数递归
tree.forEach(item => {
    item.children = array2Tree(arr,item.id)
})
// (3)返回数组tree
return tree
}

4.首先传入整个数组和,pid为空字符(先筛选出一级目录)

const newList=array2Tree(arr,'')

完整代码如下:

  <script>
    const arr=[
{'id':'29','pid':'','name':'总裁办'},
{"id":'2c','pid':'','name':'财务部'},
{'id':'2d','pid':'2c','name':'财务核算部'},
{'id':'2f','pid':'2c','name':"薪资管理部"},
{'id':'d2','pid':'','name':'技术部'},
{'id':'d3','pid':'d2','name':'java技术部'},
{'id':'e1','pid':'d3','name':'spring技术部'},
]
// 数组转树的封装函数
function array2Tree(arr,pid){
// (1)筛选出pid相同的数组元素怒
const tree =arr.filter( item => item.pid === pid)

// (2)对筛选出的tree数组增加children数组,调用本函数递归
tree.forEach(item => {
    item.children = array2Tree(arr,item.id)
})
// (3)返回数组tree
return tree
}
// 首先传入整个数组和,pid为空
const newList=array2Tree(arr,'')
console.log(newList);
    </script>

实现效果如图:

image.png