前端项目开发中,虽然大多数数据后端都会处理好给我们,但是基于前后端分离的趋势等原因,我们还是经常会遇到和树打交道的场景。对这种结构,我们最先想到的一定是递归处理,但是递归较为耗费性能,有时候也使用while来替代处理。
而这里,我来提供一种不常见的打平树的方法:
用for实现打平
。
用
for
实现的本质其实和用while
是相似的,都是操作一个动态的数组,将子项不停的拿出来放到最外层即可。
用for实现打平之:深度遍历算法
一 数组打平
核心逻辑就是使用splice
将子数组不断的拿出来插入到原来的位置上,所以每循环到一个多层的结构,就会打平掉一层。
示例
const arr = [1, [[2, [3, 4]]], 5, [6]];
方法
let flatten = (arr) => {
const copy = JSON.parse(JSON.stringify(arr)); // 拷贝一份用来生成结果
for(var i = 0; i < copy.length; i++) {
const current = copy[i];
if (Array.isArray(current)) { // 检测到当前位置存在多层
copy.splice(i, 1, ...current) // 将里层打平(...current),插入原位置替换原值
i--; // 替换过之后,当前位置需要再进行一次检查,所以这里退一位
}
}
return copy;
}
结果
console.log(flatten(arr)); // [1, 2, 3, 4, 5, 6]
二 树打平
核心逻辑就是使用splice
将children不断的拿出来插入到父级兄弟位置(后一位)上,所以子孙都会排队插到祖宗后面,最终打平。
示例
const tree = [
{
name: '小明前端专家',
id: 1,
pid: 0,
children: [
{
name: '小花前端程序媛',
id: 11,
pid: 1,
children: [
{
name: '小华划水运动员',
id: 111,
pid: 11,
},
{
name: '小李摸鱼运动员',
id: 112,
pid: 11,
}
]
},
{
name: '小红摸鱼程序员',
id: 12,
pid: 1,
}
]
},
{
name: '小王内卷王',
id: 2,
pid: 0,
children: [
{
name: '小林摸鱼王',
id: 21,
pid: 2,
},
{
name: '小李后端程序员',
id: 22,
pid: 2,
}
]
}
]
方法
let flattenTree = (tree) => {
const copy = JSON.parse(JSON.stringify(tree)); // 拷贝一份用来生成结果
for(let i = 0; i < copy.length; i++) {
const current = copy[i];
if (current.children?.length) { // 检测到当前位置存在子集
copy.splice(i + 1, 0, ...current.children) // 将children打平(...current.children),插入父级后一位
}
delete current.children; // children呗复制到了父级后面,此处删除
}
return copy;
}
结果
console.log(flattenTree);
// [
// {
// "name": "小明前端专家",
// "id": 1,
// "pid": 0
// },
// {
// "name": "小花前端程序媛",
// "id": 11,
// "pid": 1
// },
// {
// "name": "小华划水运动员",
// "id": 111,
// "pid": 11
// },
// {
// "name": "小李摸鱼运动员",
// "id": 112,
// "pid": 11
// },
// {
// "name": "小红摸鱼程序员",
// "id": 12,
// "pid": 1
// },
// {
// "name": "小王内卷王",
// "id": 2,
// "pid": 0
// },
// {
// "name": "小林摸鱼王",
// "id": 21,
// "pid": 2
// },
// {
// "name": "小李后端程序员",
// "id": 22,
// "pid": 2
// }
// ]
用for实现打平之:广度遍历算法
广度遍历
不会用于数组打平,这里就以树打平为例进行实现:
方法
let flattenTree = (tree) => {
const copy = JSON.parse(JSON.stringify(tree));
for(let i = 0; i < copy.length; i++) {
const current = copy[i];
if (current.children?.length) {
copy.push(...current.children) // 将孙子安顺序放到所有爷爷后面,实现先爷爷后孙子,即为广度遍历
}
delete current.children;
}
return copy;
}
结果
console.log(flattenTree);
// [
// {
// "name": "小明前端专家",
// "id": 1,
// "pid": 0
// },
// {
// "name": "小王内卷王",
// "id": 2,
// "pid": 0
// },
// {
// "name": "小花前端程序媛",
// "id": 11,
// "pid": 1
// },
// {
// "name": "小红摸鱼程序员",
// "id": 12,
// "pid": 1
// },
// {
// "name": "小林摸鱼王",
// "id": 21,
// "pid": 2
// },
// {
// "name": "小李后端程序员",
// "id": 22,
// "pid": 2
// },
// {
// "name": "小华划水运动员",
// "id": 111,
// "pid": 11
// },
// {
// "name": "小李摸鱼运动员",
// "id": 112,
// "pid": 11
// }
// ]
(注:代码中JSON.parse
方式的深拷贝,只是作为测试使用,实际项目请不要参考这种性能不好的方式。)
参考
整理了一系列的JavaScript树操作方法,不用再一遍又一遍的百度了 (参考了此篇文章的数据demo)