js扁平数组对象转成树结构

假如有个需求,是如下结构:

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

通过pid这个字段,要转成树结构,就是这样:

[
    {
        "id": 1,
        "name": "部门1",
        "pid": 0,
        "children": [
            {
                "id": 2,
                "name": "部门2",
                "pid": 1,
                "children": []
            },
            {
                "id": 3,
                "name": "部门3",
                "pid": 1,
                "children": [
                    {
                        "id": 4,
                        "name": "部门4",
                        "pid": 3,
                        "children": [
                            {
                                "id": 5,
                                "name": "部门5",
                                "pid": 4,
                                "children": []
                            }
                        ]
                    }
                ]
            }
        ]
    }
]

思路如下:

先把数据转成Map形式去存储,再去遍历这个Map找到对应的数据,完整代码:

let arr = [
    {id: 1, name: '部门1', pid: 0},
    {id: 2, name: '部门2', pid: 1},
    {id: 3, name: '部门3', pid: 1},
    {id: 4, name: '部门4', pid: 3},
    {id: 5, name: '部门5', pid: 4},
]
let result = []
let trees = {}

// 遍历给每一个对象添加一个children属性并转换成Map形式;并添加进trees对象,id为键
arr.forEach(item => {
    item.children = []
    trees[item.id] = item
})


// 遍历查找对应的Map做存储
arr.forEach(item => {
    // 找到pid不为0的对象
    if(trees[item.pid]){
        // 因为pid对应的父节点是id,所以通过pid找到父节点再把当前的对象添加进入子数组里面
        trees[item.pid].children.push(item)
    }
    // 把pid为0的对象添加进最终的数组result,做为父节点
    if(item.pid == 0){
        // item是引用类型(浅拷贝),针对当前数据所以只需push一次到result
        result.push(item)
    }
})

但是目前这个有个缺点,就是假如有两个父节点,就会有问题,因为这里是用的pid===0来判断的,更完整的如下:

// 假设有如下数据,需要转成树结构:
let arr = [
    { id: 1, parentId: null, name: 'a' },
    { id: 2, parentId: null, name: 'b' },
    { id: 3, parentId: 1, name: 'c' },
    { id: 4, parentId: 2, name: 'd' },
    { id: 5, parentId: 1, name: 'e' },
    { id: 6, parentId: 3, name: 'f' },
    { id: 7, parentId: 4, name: 'g' },
    { id: 8, parentId: 7, name: 'h' },
]

// 定义最终输出的数组
let trees = []

// 定义一个map
let map = new Map()

// 遍历源数组,给map添加数据,这里的map是浅拷贝,后续修改map会直接修改到arr数组
for (let v of arr){
    // set(key,value)方法:	向当前Map对象中添加一个值,返回的Map对象,所以支持链式写法
    map.set(v.id, v)
}

for (let v of arr){
    const pId = v.parentId

    // 方法has(key) 返回一个bool值,用来表明map 中是否存在指定元素.
    // 如果map中不存在当前元素parentId,则该元素为根元素,当前数据针对null,是不存在的
    if (!map.has(pId)) {
        // push的对象是引用类型(浅拷贝)
        trees.push(v)
    }

    // 如果map中存在 当前元素的parentId,则该元素不为根元素
    else {
        // get(key)	通过key找到value,如果找不到,返回undefined
        // 得到的 parent 是引用类型
        const parent = map.get(pId)

        // instanceof方法:用于判断一个变量是否某个对象的实例
        // 这里的意思是:如果parent没有children这个字段或者不是一个数组,则手动添加一个children属性为空数组
        !(parent.children instanceof Array) && (parent.children = [])

        parent.children.push(v)
    }
}
console.log(trees)

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值