给定一棵树(一个对象),然后根据传入的id查找,经常遇到有两种情况:
1)查找是否有对应的节点,有则返回该节点;
2)记录对应树节点的路径。
树的结构如下:
let tree = {
id: 1,
name: "company",
children: [
{
id: 2,
name: "group1",
children: [
{
id: 3,
name: 'dept1'
},
{
id: 5,
name: 'dept2',
children: [
{
id: 6,
name: 'user1'
}
]
},
]
},
{
id: 4,
name: "gropu2"
},
]
}
1、根据id查询tree上是否有该节点,有则返回
// 方法1: 利用递归,需要注意区分子节点是对象还是数组
let result = null // 报错最终结果
function findNodeFromTreeById(root, id) {
if (!!root) {
let type = Object.prototype.toString.call(root).slice(8, -1)
if (type === 'Object') {
if (root.id && root.id === id) {
result = root
} else {
let node = root.children || null
findNodeFromTreeById(node, id)
}
} else if (type === 'Array') {
let needNode = root.find(x => !!x === true && x.id === id)
if (!!needNode) {
result = needNode
} else {
root && root.forEach(item => {
if (item && item.children && item.children.length) {
findNodeFromTreeById(item.children, id)
}
})
}
}
}
return result
}
// test
getNodeById(testTree, 4) // {id: 4, name: 'group2'}
findFromTreeById(testTree, 5) // {id: 5, name: 'dept2', children: [{id: 6, name: 'user1'}]}
// 方法2: 将tree变成一个数组
function getNodeById(tree, id) {
let arr = Array.isArray(tree) ? tree : [tree]
let result = null
while (arr.length) {
let item = arr.pop()
if (item && item.id === id) {
result = item
break
} else if (item && item.children && item.children.length) {
arr.push(...item.children)
}
}
return result
}
// test
getNodeById(tree, 4)) // { id: 4, name: 'group2' }
getNodeById(tree, 7)) // null
2、根据id查找tree中对应节点路径
// 利用递归,将tree转化成数组结构来操作
function getPathById(tree, id, path) {
tree = Array.isArray(tree) ? tree : [tree]
if (!path) {
path = []
}
for (let i = 0, len = tree.length; i < len; i++) {
let tempPath = [...path]
tempPath.push(tree[i].name)
if (tree[i].id === id) {
return tempPath
}
if (tree[i].children) {
return getPathById(tree[i].children, id, tempPath)
}
}
}
// test
getPathById(tree, 3) // ['company', 'group1', 'dept1']
getPathById(tree, 8) // null