JS通过递归,处理树型结构数据
Posted Dormiveglia-flx
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS通过递归,处理树型结构数据相关的知识,希望对你有一定的参考价值。
JS通过递归,处理树型结构数据
为什么要将扁平化的数据,变成树型结构?
// 比如这样的数据,后台给的是扁平化数据,前端需要制作成树型结构,供vue-router使用
const routeData = [
id:1,
pid:0,
name:'菜单subMenu-1'
,
id:2,
pid:0,
name:'菜单subMenu-2'
,
id:3,
pid:1,
name:'SBM-1-Menu-1'
]
先从一个简单的例子开始
现在的数据只有两级:
最终的树型结构是:
菜单subMenu-1
SBM-1-Menu-1
SBM-1-Menu-2
菜单subMenu-2
SBM-2-Menu-1
SBM-2-Menu-2
思路:
1.
找到顶级的item元素(pid==0),放到数组parents中。
找到剩余的item元素(pid!=0),放到数组children中。
2.
遍历两个数组。当顶级的id == 子级的pid的时候。给顶级添加children,并把子级push进去。
const routeData = [
id:1,
pid:0,
name:'菜单subMenu-1'
,
id:2,
pid:0,
name:'菜单subMenu-2'
,
id:3,
pid:1,
name:'SBM-1-Menu-1'
,
id:4,
pid:1,
name:'SBM-1-Menu-2'
,
id:5,
pid:2,
name:'SBM-2-Menu-1'
,
id:6,
pid:2,
name:'SBM-2-Menu-2'
]
function ArrayToTree(routeData)
// 1 先找出顶级的元素,把顶级元素放数组里面
const parents = routeData.filter(item=>
return item.pid==0;
)
// 2 把第二级元素组成数组.
//然后顶级数组与第二级数组一起遍历。找到顶级的id===子级的pid
const children = routeData.filter(item=>
return item.pid!=0;
)
//console.log(children)
parents.map(pitem=>
children.map(citem=>
// 子级的pid===顶级的id
if(citem.pid==pitem.id)
// 没有children就创建一个,有的话就直接push
if(pitem.children)
pitem.children.push(citem)
else
pitem.children = [citem]
)
)
// 使用map,会返回一个新的数组,而不改变原数组
//console.log(routeData)
//console.log(parents)
return parents
ArrayToTree(routeData)
// 这个时候,一个树型结构就出现了。
进入主题:
如果将来菜单的级数特别多怎么办?
菜单subMenu-1
SBM-1-Menu-1
SBM-1-Menu-1-1
SBM-1-Menu-1-1-1
SBM-1-Menu-2
菜单subMenu-2
SBM-2-Menu-1
SBM-2-Menu-1-1
SBM-2-Menu-2
菜单subMenu-3
这个时候,也是需要 遍历两个数组。当顶级的id == 子级的pid的时候,添加children。也就是说顶级的id == 子级的pid,添加children并push
需要执行多遍
,且不知道具体执行多少遍
(不知道有几级)的时候,可以用递归
// 那如果有无限制级子级数据,应该怎么做? -----递归
const routeData2 = [
id:1,
pid:0,
name:'菜单subMenu-1'
,
id:2,
pid:0,
name:'菜单subMenu-2'
,
id:3,
pid:1,
name:'SBM-1-Menu-1'
,
id:4,
pid:1,
name:'SBM-1-Menu-2'
,
id:5,
pid:2,
name:'SBM-2-Menu-1'
,
id:6,
pid:2,
name:'SBM-2-Menu-2'
,
id:7,
pid:3,
name:'SBM-1-Menu-1-1'
,
id:8,
pid:3,
name:'SBM-1-Menu-1-2'
,
id:9,
pid:7,
name:'SBM-1-Menu-1-1-1'
,
id:10,
pid:8,
name:'SBM-1-Menu-1-2-1'
]
// 按照刚才分配两个的思路,递归的话,主要是递归 id==citem.pid
function ArrayToTree2(routeData)
// 1 先找出顶级的元素,把顶级元素放数组里面
const parents = routeData.filter((item)=>
return item.pid==0
)
// 2 把第二级元素组成数组.
//然后顶级数组与第二级数组一起遍历。找到顶级的id===子级的pid
const children = routeData.filter(item=>
return item.pid!=0;
)
Findchildren(parents,children)
function Findchildren(parents,children)
parents.map(pitem=>
children.map((citem,index)=>
// 子级的pid===顶级的id
if(citem.pid==pitem.id)
const myChildren = JSON.parse(JSON.stringify(children))
//myChildren.splice(index,1) 优化一下
Findchildren([citem],myChildren)
// 没有children就创建一个,有的话就直接push
if(pitem.children)
pitem.children.push(citem)
else
pitem.children = [citem]
)
)
console.log(parents)
ArrayToTree2(routeData2)
// 在这里,递归可以理解成代码的嵌套,每次遇到 Findchildren ,就把这个给换成代码体里面的内容。也就是当有多级的时候,就会有多层嵌套,比如:
parents.map(pitem=>
children.map(citem=>
parents.map(pitem=>
children.map(citem=>
parents.map(pitem=>
children.map(citem=>
...里面是函数体的内容,传的参数不一样
)
)
)
)
)
)
sqlite 树型结构查询
表结构:tblCity(ID, ParentID, Name)
因为sqlite 没有row_number函数,也不能递归查询,所幸它有RowID 这个字段。只好采用这种 笨方法
1)
select ID,Name,1 as Level from tblCity where ParentID=0
union all
select a.ID,a.Name,c.RowID as Level from tblCity a
inner join tblCity b on a.ParentID=b.ID
inner join
(
select ParentID from tblCity group by ParentID
) c on a.ParentID=c.ParentID
2)
select ID,Name,1 as Level from tblCity where ParentID=0
union all
select a.ID,a.Name,c.RowID as Level from tblCity a
inner join tblCity b on a.ParentID=b.ID
inner join
(
select ParentID from tblCity group by ParentID
) c on a.ParentID=c.ParentID
以上是关于JS通过递归,处理树型结构数据的主要内容,如果未能解决你的问题,请参考以下文章