数据源:
let arr = [
{ id: 4, pid: 2, name: 'd' },
{ id: 1, pid: 0, name: 'a' },
{ id: 3, pid: 1, name: 'c' },
{ id: 5, pid: 0, name: 'e' },
{ id: 7, pid: 6, name: 'f' },
{ id: 6, pid: 5, name: 'f' },
{ id: 78, pid: 1, name: 'h' },
{ id: 8, pid: 1, name: 'g' },
{ id: 2, pid: 0, name: 'b' },
]
第一种方案核心思想:父亲找孩子+递归
实现思路:
1、将数组分成两类,父节点和子节点,parent,originChildren。
2、遍历父节点找孩子,如果找到孩子就把孩子放到父节点children属性的数组中。
3、通过递归将让子节点去找它的下级子节点。
疑点:children和originChildren是引用类型,引用类型的特点就是指向同一个引用地址的变量,无论是哪一个修改了数据源,他们获取到的数据都是保持一致;
代码如下:
function toTree(arr, pid) {
const parent = arr.filter(p => p.pid === pid),
originChildren = arr.filter(c => c.pid !== pid);
for (let p of parent) {
findChildren(p, originChildren)
}
function findChildren(p, originChildren) {
let _p = undefined;
//遍历查找当前父节点的所有孩子
for (let index = 0; index < originChildren.length; index++) {
if (originChildren[index].pid === p.id) {
// 把找到的子节点从子节点的数据源中剔除,
// 目的是减少子节点数据源的个数,提高命中率。
_p = originChildren.splice(index, 1)[0];
//由于删除了当前下标对应的元素,导致数组后面的元素往前移动,
//所以要把当前下标往前移一位。
index = index - 1; //
if (p.children) {
p.children.push(_p)
} else {
p.children = [_p]
}
findChildren(_p, originChildren)
}
}
}
return parent
}
调用:console.log(toTree(arr));
第二种方案的核心思想:孩子找父亲+map;
实现思路:
1、遍历数组,以元素的id为键,元素为值 ;添加到map中;
2、遍历数组,如果元素的pid等于parentId(根元素),直接添加到res数组中
3、否则提高map.get(item.pid)获取父节点(孩子找父亲)
实现代码:
function toTree(data, parentId = 0) {
let map = new Map(),
res = [];
data.forEach(item => map.set(item.id, item));
data.forEach(item => {
let { pid } = item,
parent = undefined;
if (pid === parentId) {
res.push(item)
} else {
parent = map.get(pid);
parent.children ? parent.children.push(item) : parent.children = [item]
}
})
return res
}
console.log(toTree(arr, 0));
map可以换成object或者数组:通过属性后绑定,代码如下:
function toTree(data, parentId = 0) {
let map ={},
res = [];
data.forEach(item => map[item.id]=item);
console.log(map);
data.forEach(item => {
let { pid } = item,
parent = undefined;
if (pid === parentId) {
res.push(item)
} else {
parent = map[pid];
parent.children ? parent.children.push(item) : parent.children = [item]
}
})
return res
}