一维数组转成树形结构
源数据:
export const regions = [
{
'code': '51',
'name': '四川省',
'pid': '0' // 区域的父级区域 id
},
{
'code': '5101',
'name': '成都市',
'pid': '51' // 成都的父级是四川省,所以 pid 是 51
},
{
'code': '510104',
'name': '锦江区',
'pid': '5101'
},
{
'code': '50',
'name': '重庆市',
'pid': '0'
},
{
'code': '5001',
'name': '市辖区',
'pid': '50'
},
{
'code': '500101',
'name': '万州区',
'pid': '5001'
}
// ...
]
转换成树结构:
[
{
"code": "51",
"name": "四川省",
"pid": "0",
"children": [
{
"code": "5101",
"name": "成都市",
"pid": "51",
"children": [
{
"code": "510104",
"name": "锦江区",
"pid": "5101",
"children": [ ]
}
]
}
]
},
{
"code": "50",
"name": "重庆市",
"pid": "0",
"children": [
{
"code": "5001",
"name": "市辖区",
"pid": "50",
"children": [
{
"code": "500101",
"name": "万州区",
"pid": "5001",
"children": [ ]
}
]
}
]
}
]
toTree
函数接收的参数regions代表一维数据数组,rootId代表树形结构中根节点的pid。toTree
函数返回的是指定根节点(pid=rootId的)的树结构,所以我们只需逐渐降低rootId,递归调用toTree
函数不断获取下一层的树形结构即可。
常规方法:
function toTree(regions, rootId) {
// TODO: 在这里写入具体的实现逻辑
// 将平铺的结构转化为树状结构,并将 rootId 下的所有子节点数组返回
// 如果不存在 rootId 下的子节点,则返回一个空数组
const arr = []
for (let i = 0; i < regions.length; i++) {
if (regions[i]['pid'] === rootId) {
regions[i].children = toTree(regions, regions[i]['code'])
arr.push(regions[i])
}
}
return arr
}
console.log(JSON.stringify(toTree(region, '0')))
toTree
函数执行一次就找到了一层数据,每一个数据被找到时就开始以该数据为根节点去递归调用toTree
函数找下一层的数据。每一次调用toTree
函数就会遍历一遍regions数组,如果最终的树形结构有三层,那么就需要遍历三遍regions数组。
高级方法:
function toTree(regions, rootId) {
// TODO: 在这里写入具体的实现逻辑
// 将平铺的结构转化为树状结构,并将 rootId 下的所有子节点数组返回
// 如果不存在 rootId 下的子节点,则返回一个空数组
return regions.reduce((result, current) => {
if (current['pid'] === rootId) {
current.children = toTree(regions, current['code'])
result.push(current)
}
return result
}, [])
}
console.log(JSON.stringify(toTree(region, '0')))
reduce的第二个参数是一个空数组,所以:
第一次执行时,result=[],current=regions[0]。然后进行判断,如果current是根节点的话就以current的id作为下一层根节点pid递归调用toTree
得到下一层的数据赋值给current.children,之后将current添加进result中,随后return出result。
第二次执行时,result为第一次执行返回的数组,current=regions[1]
第三次执行时,result为第二次执行返回的数组,current=regions[2]
…
通过子节点,查找上级所有父节点
使用上面我们转换成树形结构数据,通过区域code找到所有的父节点
展示结果:
输入"锦江区"时,返回 [ “四川省”, “成都市”, 锦江区 ]。
输入"成都市", 则返回 [ “四川省”, “成都市” ]。
输入"四川省", 则返回 [ “四川省” ]。
方法一
function findParents(regionName, regions) {
const arr = []
const findFn = (name, tree) => {
for (const item of tree) {
if (item.name === name) {
arr.unshift(item)
return true
} else if (item.children && Array.isArray(item.children) && item.children.length) {
const result = findFn(name, item.children)
if (result) {
arr.unshift(item)
return true
}
}
}
return false
}
findFn(regionName, regions)
return arr.map(item => item.name)
}
console.log(findParents('锦江区', regionsTree))//[ “四川省”, “成都市”, 锦江区 ]
方法二
const getParents = (regionName, tree) => {
for (const index in tree) {
if (tree[index]['name'] === regionName) {
return [tree[index]]
}
if (tree[index].children) {
const node = getParents(regionName, tree[index].children)
if (node !== undefined) {
const rsNode = node.concat(tree[index])
return rsNode
}
}
}
}
console.log(console.log(getParents('锦江区', regionsTree).reverse().map(item => item.name)))//[ “四川省”, “成都市”, 锦江区 ]
方法三
const reduceParents = (regionName, tree) => {
return tree.reduce((pre, current) => {
if (current['name'] === regionName) {
pre.push(current)
}
if (current.children) {
const node = reduceParents(regionName, current.children)
if (node.length > 0) {
const pre = node.concat(current)
return pre
}
}
return pre
}, [])
}
console.log(console.log(reduceParents('锦江区', regionsTree).reverse().map(item => item.name)))//[ “四川省”, “成都市”, 锦江区 ]