最近在项目中遇到一个问题
将后台返回的扁平数据结构,转成树
数据内容如下
转换成大概像下面这个形式
treeData: [
{
"id": 1,
"name": "部门1",
"pid": 0,
"children": [
{
"id": 2,
"name": "部门2",
"pid": 1,
"children": []
},
{
"id": 3,
"name": "部门3",
"pid": 1,
"children": [
{
"id": 4,
"name": "部门4",
"pid": 3,
"children": []
},
]
}
]
}
]
递归
首先想到的是递归
在上一篇已经研究过js的三种循环性能,所以这次遍历采用了foreach实现
<script>
let arr = [
{ id: 1, name: '部门1', pid: 0 },
{ id: 2, name: '部门2', pid: 1 },
{ id: 3, name: '部门3', pid: 1 },
{ id: 4, name: '部门4', pid: 3 },
{ id: 5, name: '部门5', pid: 4 },
]
function transTree (list, rootValue) { // list: 整个数组, rootValue本次要查找的目标id -> 此函数为了找到rootValue目标id的下属们
const treeData = [] // 装下属对象的
list.forEach(item => {
if (item.pid === rootValue) { // 当前对象pid符合, 继续递归调用查找它的下属
const children = transTree(list, item.id) // 返回item对象下属数组
if (children.length) {
item.children = children // 为item添加children属性保存下属数组
}
treeData.push(item) // 把当前对象保存到数组里, 继续遍历
}
})
return treeData // 遍历结束, rootValue的id对应下属们收集成功, 返回给上一次递归调用children, 加到父级对象的children属性下
}
let data = transTree(arr, 0)
console.log(data);
</script>
Map
还有一个想法是通过Map,先把数据转成Map
去存储,之后遍历的同时借助对象的引用
,直接从Map
找对应的数据做存储
function transTree2 (items) {
const result = []; // 存放结果
const Map = {};
items.forEach(item => {
const id = item.id;
const pid = item.pid;
//若没有该部门,创建
if (!Map[id]) {
Map[id] = {
children: [],
}
}
//将该部门放入Map中
Map[id] = {
...item,
children: Map[id]['children']
}
const treeItem = Map[id];
if (pid === 0) { //如果是一级部门直接插入结果数组中
result.push(treeItem);
} else {
if (!Map[pid]) { //若没有一级部门,创建
Map[pid] = {
children: [],
}
}
Map[pid].children.push(treeItem) //通过Map将该部门放入对应父部门中
}
})
return result;
}
data = transTree2(arr)
console.log(data);
对比两种方式性能
mock模拟数据
const data = Mock.mock({
'list|9999': [
{
name: '@cname',
address: '@city(true)',
'id|+1': 1,
'pid|': function () {
if (this.id % 4 === 0) {
return this.id + 1
}
if (this.id % 2 === 0) {
return this.id == 2 ? 0 : 2
}
else return this.id == 3 ? 0 : 3
}
}
]
})
const arr = data.list
console.log(arr)
function transTree (list, rootValue) {
...
}
console.time('1')
let res = transTree(arr, 0)
console.timeEnd('1')
console.log(res)
function transTree2 (items) {
...
}
console.time('2')
res = transTree2(arr)
console.timeEnd('2')
console.log(res)
数据量小的时候差别不大,但是数据量变大采用递归方式实现会越来越慢