递归实现简单的数组转树

102 阅读2分钟

递归实现简单的数组转树

先来一组数据

let data =[
    {id:1,name:'部门A',parentId:0},
    {id:2,name:'部门B',parentId:0},
    {id:3,name:'部门C',parentId:1},
    {id:4,name:'部门D',parentId:1},
    {id:5,name:'部门E',parentId:2},
    {id:6,name:'部门F',parentId:3},
    {id:7,name:'部门G',parentId:2},
    {id:8,name:'部门H',parentId:4}
];

数据中有 id / name / parentId 三个属性,我们要将 parentId 为 某个对象的 id 的对象,添加为该对象的属性

简单分析一下,第一步,我们需要遍历数组,将传入的id对应的子节点找出来

arr2tree(data, id) {
    const children = data.filter(item => {
        return item.parentId === id
    })
    return children
}

这样,我们就获得了第一层的所有子节点

那么,这显然不够,我们还需要获取下一层的子节点,而获取的代码显然是相同的,我们自然想到了递归来实现,那么问题就是在哪里开始递归

我的想法是,我们确定某个 item 属于当前的子节点时,开始递归,然后将获取到的当前item的子节点赋值到 item 上

const arr2tree = (data, id) => {
    const children = data.filter(item => {
        if(item.parentId === id) {
            //我们要获取到当前item的子节点,就将item的id作为参数传入
            item.children = arr2tree(data, item.id)
            //不要忘记将当前查找到的子节点添加到父节点的属性中
            return true
        }
    })
    return children
}

最后写一个困扰我的疑问: 以上的方法找到的最后一个子节点都会添加一个空数组到它的 children属性 中,这显然不好,所以要写一个判断解决这个问题

然后问题就来了

const arr2tree = (data, id) => {
    const children = data.filter(item => {
        if(item.parentId === id) {
            //先不急着加属性,先判断长度是否为0
            const childrenArr = arr2tree(data, item.id)
            if(childrenArr.length) {
                item.children = childrenArr
                return true
            }
        }
    })
    return children
}

结果为空数组

原因很简单,return 的位置错了,要理解 item只要存在就必须return到filter的结果里, 而我这样写,在递归的最后一层,当 item没有子节点时, item添加到children里,再往上每层都会出这个问题,最后导致空数组

正确答案:

const arr2tree = (data, id) => {
    const children = data.filter(item => {
        if(item.parentId === id) {
            //先不急着加属性,先判断长度是否为0
            const childrenArr = arr2tree(data, item.id)
            if(childrenArr.length) {
                item.children = childrenArr
            }
            return true
        }
    })
    return children
}