前端扁平化数组转树结构

应用场景

在业务中我们可能会开发树状组件或者用一些ui库的Tree组件,例如antd的Tree。如果不使用异步加载,通常后端会返回一个完整的树结构数据给前端,但也有例外的情况,后端给的是一个扁平化的数据,例如这样:

const arr = [
   {id: 1, name: '部门1', pid: 0},
   {id: 2, name: '部门2', pid: 4},
   {id: 3, name: '部门3', pid: 1},
   {id: 4, name: '部门4', pid: 3},
   {id: 5, name: '部门5', pid: 4},
   {id: 6, name: '部门1', pid: 0},
   {id: 7, name: '部门1', pid: 6},
 ]

这个时候就需要我们去将其处理为一颗树结构数据了。

实现方式

  1. 第一种方式:递归实现

    递归的弊端在于存在性能瓶颈,大量数据的情况可能不太适合。

    function customTree1 (arr, parentKey, pid = 0) {
      return arr.reduce((total, it) => {
        if (pid === it[parentKey]) {
          it.children = tree(arr, it.id)
          total.push(it)
        }
        return total
      }, [])
    }
    
  2. 第二种方式: 利用对象的弱引用实现

    相对与递归,因为只有一层遍历,性能上要更好一些。写法有很多种,这里只列了两种写法,但实现思路都是一样的,利用map数据结构创建一个字典,遍历数据设置子节点。时间和空间复杂度没算过,有兴趣的可以自己算一下。

    • 第一种:

      function customTree2 (baseData, parentKey, rootId = 0) {
        const map = {}
        const result = []
        arr.sort((a,b) => a[parentKey] - b[parentKey])
        arr.forEach(it => {
          if (!map[it.id]) {
            map[it.id] = {
              children: []
            }
          }
          map[it.id] = {
            ...it,
            children: map[it.id]['children']
          }
          
          const parent = map[it.id]
          if (it[parentKey] === rootId) {
            result.push(parent)
          } else {
            if (map[it.pid] && map[it[parentKey]].children) {
              map[it[parentKey]].children.push(parent)
            }
          }
        })
        return result
      }
      
    • 第二种:

      function customTree3 (baseData = [], parentKey, rootId = 0) {
        try {
          const result = []
      
          // 创建一个数据字典
          const dictionary = baseData.reduce((pre, cur) => {
            pre[cur.id] = { ...cur, children: [] }
            return pre
          }, {})
      
          baseData.forEach(item => {
            const parent = dictionary[item[parentKey]]
            if (parent) parent.children.push(dictionary[item.id]) // 在字典中查找对应的数据并修改它的children
            else result.push(dictionary[rootId || item.id]) // 如果没找到就代表是根节点,或者指定一个根节点
          })
      
          return result
        } catch (e) {
          console.error(e)
          return []
        }
      }
      
  3. 使用

    const data1 = customTree1(arr, 'pid')
    const data2= customTree2 (arr, 'pid')
    const data3 = customTree3(arr, 'pid')
    console.log('🚀 --- ~ data1', data1)
    console.log('🚀 --- ~ data2', data2)
    console.log('🚀 --- ~ data3', data3)
    
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值