list/Arrray数据转树形数据
const treeData = [
{ id: '1000', pid: null, name: '西安总部' }, // 1级
{ id: '10001', pid: '1000', name: '西安雁塔分部 - 子公司' }, // 2级
{ id: '10002', pid: '1000', name: '西安莲湖分部 - 子公司' }, // 2级
{ id: '100021', pid: '2000', name: '西安莲湖分部 - 西桃园分部 - 子公司' }, // 3级
{ id: '2000', pid: null, name: '北京总部' }, // 1级
{ id: '20001', pid: '2000', name: '北京丰台分部 - 子公司' }, // 2级
{ id: '20002', pid: '2000', name: '北京朝阳分部 - 子公司' }, // 2级
{ id: '200021', pid: '1000', name: '北京朝阳分部 - 广渠路分部 - 子公司' } // 3级
]
// 方法1
const listToTree1 = (list = [], option = {}) => {
option.selfKey = option.selfKey ? option.selfKey : 'id'
option.parentKey = option.parentKey ? option.parentKey : 'pid'
option.childrenKey = option.childrenKey ? option.childrenKey : 'children'
const tree = []
const idMapping = list.reduce((acc, item, index) => {
acc[item[option.selfKey]] = index
return acc
}, {})
for (const item of list) {
if (!item[option.parentKey]) {
tree.push(item)
continue
}
const parent = list[idMapping[item[option.parentKey]]]
parent.children = [...(parent.children || []), item]
}
return tree
}
console.log(listToTree1(treeData))
// 方法2: 递归遍历children
const listToTree2 = (list = [], pid) => {
const result = list.filter(item => {
if (item.pid === pid) {
item.children = listToTree2(list, item.id)
return true
}
return false
})
return result
}
console.log(listToTree2(treeData, null))
// 方法3: 查询每个节点的parent,查到parent之后,内部循环就可以截止了。(使用find方法)
const listToTree3 = (list = [], pid) => {
const result = list.filter(item => {
if (item.pid !== pid) {
let parent = list.find(parent => parent.id = item.pid)
if(!parent.children) parent.children = []
parent.children.push(item)
return false
}
return true
})
return result
}
console.log(listToTree3(treeData, null))
// 方法4:在方法3的基础上,将每次find的parentNode缓存起来,减少相同parent的查询次数
const listToTree4 = (list, parentId) => {
let parentObj = {}
return list.filter(item => {
if (item.pid !== parentId) {
if (!parentObj[item.pid]) {
parentObj[item.pid] = list.find(parent => parent.id === item.pid)
parentObj[item.pid].children = []
}
parentObj[item.pid].children.push(item)
return false
}
return true
})
}
console.log(listToTree4(treeData, null))
// 方法5: 遍历tree之前,先遍历一遍数组,将数据缓存到object中。二次遍历,直接使用object中的缓存
const listToTree5 = (list) => {
let mapObj = {}
list.forEach(item => {
item.children = []
mapObj[item.id] = item
})
const result = list.filter(item => {
if (item.pid !== null) {
mapObj[item.pid].children.push(item)
return false
}
return true
})
return result
}
console.log(listToTree5(treeData))
// 该方法使用Map数据结构,将每个节点的id作为键,节点作为值存储。然后使用循环来遍历列表,将每个节点连接到其父节点。
function convertToTree(list) {
const map = new Map(list.map((item) => [item.id, item]));
const tree = [];
for (const item of list) {
if (item.parent === null) {
tree.push(item);
continue;
}
const parent = map.get(item.parent);
if (parent) {
parent.children = parent.children || [];
parent.children.push(item);
}
}
return tree;
}
convertToTree(treeData)
const data = [
{ id: 1, parentId: null, name: 'A' },
{ id: 2, parentId: 1, name: 'B' },
{ id: 3, parentId: 1, name: 'C' },
{ id: 4, parentId: 3, name: 'D' },
{ id: 5, parentId: 4, name: 'E' }
];
// 此代码通过遍历数组并使用 reduce 方法将扁平化的对象数组转换为树形结构。在 reduce 方法的初始值中创建一个空对象,
// 然后对于数组中的每个元素,如果该元素的 parentId 属性为空,则将其添加到初始对象中;否则,将其作为子节点添加到其父节点中。
// 最后,将转换后的对象中的所有值作为数组返回。
const tree = data.reduce((acc, item) => {
if (!item.parentId) {
acc[item.id] = { ...item, children: [] };
} else {
const parent = acc[item.parentId];
if (parent) {
parent.children = [...(parent.children || []), { ...item, children: [] }];
}
}
return acc;
}, {});
const result = Object.values(tree);