递归实现简单的数组转树
先来一组数据
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
}