list/Arrray數(shù)據(jù)轉(zhuǎn)樹形數(shù)據(jù)
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: 查詢每個節(jié)點的parent脖母,查到parent之后究流,內(nèi)部循環(huán)就可以截止了篓像。(使用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的查詢次數(shù)
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之前狐赡,先遍歷一遍數(shù)組撞鹉,將數(shù)據(jù)緩存到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數(shù)據(jù)結構孔祸,將每個節(jié)點的id作為鍵隆敢,節(jié)點作為值存儲发皿。然后使用循環(huán)來遍歷列表崔慧,將每個節(jié)點連接到其父節(jié)點。
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' }
];
// 此代碼通過遍歷數(shù)組并使用 reduce 方法將扁平化的對象數(shù)組轉(zhuǎn)換為樹形結構穴墅。在 reduce 方法的初始值中創(chuàng)建一個空對象惶室,
// 然后對于數(shù)組中的每個元素,如果該元素的 parentId 屬性為空玄货,則將其添加到初始對象中皇钞;否則,將其作為子節(jié)點添加到其父節(jié)點中松捉。
// 最后夹界,將轉(zhuǎn)換后的對象中的所有值作為數(shù)組返回。
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);