数组转为树
// 通常情况下,会给你排序好的数组。但不排除个别情况下考察你是否真正用过,所以会打乱顺序。因此,写出来的代码也要适用于乱序的情况
const arr = [
{id:1, name: '部门A', parentId: 0},
{id:2, name: '部门B', parentId: 1},
{id:3, name: '部门C', parentId: 1},
{id:4, name: '部门D', parentId: 2},
{id:5, name: '部门E', parentId: 2},
{id:6, name: '部门F', parentId: 3},
{id:7, name: '部门G', parentId: 4},
{id:8, name: '部门H', parentId: 4}
]
思路:
1. 遍历数组
2. 每个元素,都生成tree node
3. 找到parentNode,并加入到它的children中
问题来了:如何找到parentNode呢
首先,每个元素都有id,那么就可以使用Map来维护id与元素的关系。即有id就可以找到这个元素。然后,每个元素又有parentId,这个parentId等于父元素的id。那么就很简单了,通过parentId就能获取到parentNode了。
思路有了,问题也有了方案去解决,那么代码就跟着思路走就行
function convert(arr) {
const parentMap = new Map() // 每个元素都会把id与元素一一对应
let res = null
// 第一次循环,是为了把所有元素都放入到map中,防止传入的数组为乱序
arr.forEach(item => {
const {id, name} = item
const treeNode = {id,name}
parentMap.set(id, treeNode)
})
arr.forEach(item => {
const {id, parentId} = item // 拿到每个元素的id和parentId
const parentNode = parentMap.get(parentId) //获取该元素的父元素
if (parentNode){ // 父元素存在
if (parentNode.children == null) parentNode.children = [] // 父元素的children不存在,则设置为[]
parentNode.children.push(parentMap.get(id)) // 存在,则加入到父元素的children中
}
if (parentId === 0) res = parentMap.get(id) // 根元素
})
return res
}
输出结果如图,非常简单了
树转数组
思路:
1. 使用广度优先遍历DOM树
2. 每个节点,都生成元素
3. 找到parentId,并加入到元素中
问题来了:如何找到parentId呢?
使用广度优先遍历,拿到每个节点下的子节点,然后将子节点本身与父节点绑定加入到Map中,这样就能通过节点本身拿到父节点,进而拿到父节点的id。
function convert(tree) {
const parentMap = new Map() // 子节点与父节点一一对应
const arr = []
const queue = []
// 根元素入队
queue.unshift(tree)
while(queue.length > 0) {
const treeNode = queue.pop() // 出队
if (treeNode == null) break // 如果不存在,则跳出循环
const {id, name, children = [] } = treeNode
const parentNode = parentMap.get(treeNode) // 通过节点本身拿到父节点
const parentId = parentNode?.id || 0 // 判断父节点是否有id
const item = {id, name, parentId}
arr.push(item)
children.forEach(child => {
parentMap.set(child, treeNode) // 映射 子节点与父节点的关系
queue.unshift(child) // 入队
})
}
return arr
}
输出结果如图,非常简单了