引言
相信在面试的小伙伴,可能遇到关于数组转树形结构或者树形结构转数组的面试题,如果之前没有对算法题有所研究的小伙伴,初次遇到这个面试题的小伙伴可能有点懵。下面就由我带你轻松掌握关于它以及他的使用场景。
数组转树形的用途
为什么面试的时候会问关于它呢,其实这种树形结构的数据在项目中还是很常见的。树形结构的数据的主要用途就是供菜单渲染使用。不过这种数据的返回一般是由后端人员完成的,也不排除由前端人员转换的情况。
前端转换的场景:当我们拿到用户角色对应的菜单权限数组时,像:[home,goods,goodsmanage,chart,line]
,还拿到了整个菜单的数组列表,我们需要根据用户的权限来动态渲染出对应的菜单,此时我们应该如何处理呢?
1.根据整个菜单的数组列表和权限数组,生成该用户对应的菜单列表
2.把菜单列表转化为树形结构对象
3.根据树形结构对象渲染对应的菜单
数组转树形
现有后台返回的用户信息和完整菜单数组数据如下:
完整菜单数组
const list=[
{id:"0",pid:"",title:"菜单",key:'menu'},
{id:"1",pid:"0",title:"首页",key:'home'},
{id:"2",pid:"0",title:"商品",key:'goods'},
{id:"2-1",pid:"2",title:'商品管理',key:'goodsmanage'},
{id:"2-2",pid:'2',title:'商品分类',key:'goodscategory'},
{id:"3",pid:"0",title:"图表管理",key:'chart'},
{id:"3-1",pid:'3',title:"饼图",key:'pie'},
{id:"3-2",pid:'3',title:"条形图",key:'bar'},
{id:"3-3",pid:'3',title:"折线图",key:'line'}
]
用户信息
const user={
name:'xxx',
role:'xx'
auth:['home','goods','goodsmanage','goodscategory','chart','pie']
}
1.先找到该角色对应的菜单列表
const myList=[] // 定义该用户对应的菜单列表
for(let i of list)
{
// 如果找到用户对应的菜单项,把该菜单项加进去
if(user.auth.indexOf(i.key)!==-1) myList.push(i)
}
2.开始转树形
方法一:非递归思路
非递归思路:找到自己的还是,然后把根节点返回出去。因为根节点会收纳自己的孩子,根节点的孩子也会收纳自己的孩子,以此类推。因此我们只需要找到根节点就相当于找到整颗树形了
function createTree(arr=[]){
let res
for(let i of arr){
for(let j of arr){
if(!i.pid) res=i // 找到根节点
if(i.id==j.pid) // 让每个节点都去去寻找自己的子节点,然后将子节点收入其中
{
if(!i.children)i.children=[]
i.children.push(j)
}
}
}
return res
}
const myTree=createTree(myList)
console.log(myTree)
方法二:递归思路
找到自己的孩子,然后把根节点返回出去。让根节点找自己的子节点,然后递归子节点,让他们也去找自己的子节点,时间复杂度也是n的平方
function creatTree(arr=[],id){
let res,children=[]
arr.forEach(v=>{
if(id==v.id) {
v.children=children
res=v
}
if(v.pid==id) children.push(v)
children.forEach(v=>{creatTree(arr,v.id)})
})
return res
}
const myTree=createTree(list,"0") // 0是根节点的id
console.log(myTree)
3.渲染菜单,以antd
的Menu
组件为例。
import {PureComponent} from "react"
import {Menu} from 'antd'
class index extends PureComponent{
linkto=(i)=>{
this.props.history.push(`${this.props.match.path}/${i.keyPath.reverse().join('/')}`)
}
render() {
return (
<div className='leftnav'>
<Menu
defaultSelectedKeys={keys}
defaultOpenKeys={keys}
mode="inline"
theme="dark"
items={this.state.myTree.children} {/*这里的myTree就是上面的树形数据*/
onClick={this.linkto}
/>
</div>
)
}
}
export default index
树形转数组
其实树形结构转数组涉及到了数据结构关于树的算法,例:先序遍历、中序遍历、后序遍历、层序遍历,区别就在于节点输出的顺序不一致。如果想了解关于树的这些算法,可以看看我发布的一篇文章——>js实现树的前、中、后、层序遍历。
function treeToList(obj={}){
const res=[]
function a(obj={}){
res.push({id:obj.id,pid:obj.pid})
if(obj.children){
for(let v of obj.children){
a(v)
}
}
}
a(obj)
return res
}
const list=treeToList(myTree)
console.log(list)
结尾
感谢你的观看,希望这篇文章能给你带来快乐。如果有小伙伴有一些问题或者疑惑,欢迎提出和分享。