const treeData=[
{id:1,
name:'中国',
children:[
{
id:11,
name:'河南省',
children:[
{
id:111,
name:'南阳市',
children:[
{
id:1111,
name:'淅川县',
children:null
}
]
},
{
id:112,
name:'郑州市',
children:[
{
id:1121,
name:'中牟县',
children:null
}]
}
]
},
{
id:22,
name:'广东省',
children:[
{
id:221,
name:'深圳市',
children:[
{
id:2211,
name:'宝安区',
children:null
},{
id:2212,
name:'福田区',
children:null
}
]
},
{
id:222,
name:'广州市',
children:[{
id:2221,
name:'天河区',
children:null
},{
id:2222,
name:'南沙区',
children:null
}]
}
]
}]}
]
const listData1=[
{id:1,name:'中国'},
{id:11,name:'河南省',pid:1},
{id:111,name:'南阳市',pid:11},
{id:1111,name:'淅川县',pid:111},
{id:112,name:'郑州市',pid:11},
{id:1121,name:'中牟县',pid:112},
{id:12,name:'广东省',pid:1},
{id:121,name:'深圳市',pid:12},
{id:1211,name:'宝安区',pid:121},
{id:1212,name:'福田区',pid:121},
{id:122,name:'广州市',pid:12},
{id:1221,name:'天河区',pid:122},
{id:1222,name:'南沙区',pid:122},
]
1、一维数组转树形结构
1.1、递归
//一维数组转树形结构
function listToTree(list){
const tree=[]
for(const node of list){
//如果是父节点
if(!node.pid){
let p={...node}
p.children=getChildren(p.id,list)
tree.push(p)
}
}
return tree
}
function getChildren(id,list){
const children=[]
//遍历数组的每一个元素,如果找到元素的父元素节点等于当前节点,则向children中添加该元素
for(const node of list){
if(node.pid===id){
children.push(node)
}
}
//遍历每一个孩子节点,递归寻找孩子的孩子节点,如果存在children,则向node的children中添加
for(const node of children){
const children=getChildren(node.id,list)
if(children.length){
node.children=children
}
}
return children
}
demo:
console.log(listToTree(listData))
打印后的结果和treeData一致。
1.2、双层循环
// 双层循环:找出每一个元素的父节点,向每一个父节点增加children属性
function listToTree2(list){
list.forEach(child=>{
const pid=child.pid
//遍历子节点,然后遍历每一个list节点,从中找出父节点,向父节点增加孩子元素
if(pid){
list.forEach(parent=>{
if(parent.id===pid){
//如果找到的父节点还没有孩子,会默认为空数组,否则为原来的子节点数组
parent.children=parent.children||[]
parent.children.push(child)
}
})
}
})
}
结果同1.1
1.3、使用map
//Map
function listToListMap(list){
const [map,treeData]=[{},[]]
//将map转为以id为key,索引为value的对象
//将数组中每个元素的children初始化为空数组
for(let i=0;i<list.length;i++){
map[list[i].id]=i;
list[i].children=[]
}
console.log(map)
for(let i=0;i<list.length;i++){
const node=list[i]
//如果是子元素并且子元素的父节点存在在list中,则找到父元素并向父元素的children中加入子元素
if(node.pid&&list[map[node.pid]]){
list[map[node.pid]].children.push(node)
}else{
//说明不是子元素,是父元素直接放入treeData中
treeData.push(node)
}
}
return treeData
}
2、tree转list
树形结构转数组涉及到树的遍历,树的遍历分为深度遍历(前中后序)和广度遍历。
2.1、广度遍历
const treeData3=[
{id:1,
name:'中国',
children:[
{
id:11,
name:'河南省',
children:[
{
id:111,
name:'南阳市',
pid:11,
children:[
{
id:1111,
name:'淅川县',
children:null,
pid:111,
}
]
},
{
id:112,
name:'郑州市',
pid:11,
children:[
{
id:1121,
pid:112,
name:'中牟县',
children:null
}]
}
]
},
{
id:22,
name:'广东省',
children:[
{
id:221,
pid:22,
name:'深圳市',
children:[
{
id:2211,
pid:221,
name:'宝安区',
children:null
},{
id:2212,
pid:221,
name:'福田区',
children:null
}
]
},
{
id:222,
pid:22,
name:'广州市',
children:[{
id:2221,
pid:222,
name:'天河区',
children:null
},{
id:2222,
pid:222,
name:'南沙区',
children:null
}]
}
]
}]}
]
//广度遍历(一层一层遍历)
function treeToList(treeData){
const list=[]
const queue=[...treeData]
while(queue.length){
//取队头元素
const node=queue.shift()
const children=node.children
//将队头元素的孩子依次放入队列中便于后序遍历
if(children){
queue.push(...children)
}
//放入元素节点
list.push(node)
}
return list
}
console.log(treeToList(treeData3))
打印结果同1中的listData
2.2、深度遍历
//深度遍历(采用栈)
function treeToList2(tree){
const list=[]
const stack=[...tree]
while(stack.length){
const node=stack.pop()
//如果出栈的节点有孩子元素,那么将出栈元素的所有孩子元素都放入栈中,便于后续遍历.
const children=node.children
if(children){
stack.push(...children)
}
list.push(node)
}
return list
}
3、list转Map(map是以父节点id为key,所有子节点作为数组为value的数据结构)
const listData4=[
{id:1,name:'中国'},//0
{id:11,name:'河南省',pid:1},//1
{id:111,name:'南阳市',pid:11},//2
{id:1111,name:'淅川县',pid:111},//3
{id:112,name:'郑州市',pid:11},//4
{id:1121,name:'中牟县',pid:112},//5
{id:12,name:'广东省',pid:1},//6
{id:121,name:'深圳市',pid:12},//7
{id:1211,name:'宝安区',pid:121},//8
{id:1212,name:'福田区',pid:121},//9
{id:122,name:'广州市',pid:12},//10
{id:1221,name:'天河区',pid:122},//11
{id:1222,name:'南沙区',pid:122},//12
]
// 将列表数据转为以父节点id为key,子节点为value的map
function listToMap(list){
const map={}
list.forEach(item=>{
for(let i=0;i<list.length;i++){
//如果外层循环元素的id等于内层循环元素的pid,说明内层元素是外层元素的子元素,则向map的value中添加该内层元素.
if(list[i].pid===item.id){
map[item.id]=map[item.id]||[]
map[item.id].push(list[i])
}
}
})
return map
}
console.log(listToMap(listData4))