遍历数组
遍历tree,并console.log所有id
const tree = [ { id: '1', children: [ { id: '1-1' }, { id: '1-2', children: [ { id: '1-2-1' }, { id: '1-2-2' }, { id: '1-2-3' }, ]
},
]
},
{ id: '2',
children: [
{ id: '2-1',
children: [
{ id: '2-1-1' },
{ id: '2-1-2' },
{ id: '2-1-3' },
]
},
{ id: '2-2' },
]
},
{ id: '3' }
]
递归(经常用到)
function recursive(tree, cb) {
tree?.forEach(item => {
cb?.(item)
recursive(item.children, cb) // 递归
})
}
recursive(tree, item => console.log(item.id))
迭代
由于浏览器存在调用栈溢出情况(当然,一般我们遇不到),我们便使用迭代替代递归
function iteration(tree, cb) {
const list = [...tree]
while (list.length) { // 相当于迭代list
const item = list.shift() // 从数组第一项取,直到取完
cb?.(item)
if (item.children) {
list.unshift(...item.children) // 将子节点加到数组前面
}
}
}
iteration(tree, item => console.log(item.id))
数组转树
可能服务端偷懒,没有帮我们转换树结构,这个时候需要我们前端自行转换
const list = [
{ id: '1', text: '祖先1' },
{ id: '2', text: '祖先2' },
{ id: '3', text: '祖先3' },
{ id: '4', text: '子1', pid: '1' },
{ id: '5', text: '子2', pid: '2' },
{ id: '6', text: '子3', pid: '3' },
{ id: '7', text: '子3', pid: '3' },
{ id: '8', text: '叶子1', pid: '4' },
{ id: '9', text: '叶子2', pid: '4' },
{ id: '10', text: '叶子3', pid: '6' },
]
// 先混淆,表示祖先和叶子出现的顺序未定
function confusion(l = []) {
return l.sort(() => 0.5 - Math.random())
}
const arr = confusion(list)
为了减少遍历次数,采用空间换时间,创建一个map<id, item>用于记录每一项。而后遍历时,添加至pid于map中存在的项中。如果pid于map中不存在,则先创建,等后续遍历到时再替换。
function listToTree(arr) {
const map = new Map()
arr.forEach((item) => {
let pItem = map.get(item.pid)
// 保证父项的存在
if (!map.has(item.pid)) {
map.set(item.pid, pItem = { children: [] })
}
if (!pItem.children) {
pItem.children = []
}
// 将当前项添加至父项中
pItem.children.push(item)
// 如果之前存在,则替换
if (map.has(item.id)) {
item.children = map.get(item.id).children
}
// 将当前项添加至map中
map.set(item.id, item)
})
// 获取,由于顶层pid不存在,则直接获取map中的undefined
// 同时,我们也可以明确指出默认的顶层id来替代undefined
return map.get().children
}
console.log(listToTree(arr))