前言:工作中经常会遇到后台给我们一个扁平化的数据,需要我们转换成树形结构,而且我们操作过这个树形结构后,需要把操作后刚开始的那个扁平化的数据传给后台
基于上面的需求开始今天的代码,这个需求看着挺简单,但是真正做起来还是有些难度
一、一维数组转树形结构
let arr = [
{ id: 1, p_id: 0, name: '首页' },
{ id: 2, p_id: 0, name: '菜单管理' },
{ id: 3, p_id: 0, name: '菜单列表' },
{ id: 4, p_id: 1, name: '权限管理' },
{ id: 5, p_id: 6, name: '管理员列表' },
{ id: 6, p_id: 4, name: '角色列表' }
]
1.1 递归实现
思路:
1、从数组arr中取出 p_id = 0 的数据 arr_pid0 存到数组中
2、然后找他的children,怎么找children呢?
3、假设arr_pid0 的 id 为 1,那么我要从arr中取出p_id = 1的数据赋值给children就可以了
4、然而咱们的函数就是从arr中取出 p_id === rootValue 的值
5、所以const children = newArrFn(arr, cur.id)
6、cur.children = children
function newArrFn(arr, rootValue = 0) {
return arr.reduce((acc, cur) => {
if (cur.p_id === rootValue) {
const children = newArrFn(arr, cur.id)
if (children.length) {
cur.children = children
}
acc.push(cur) // 返回值 新数组的长度
}
return acc
}, [])
}
console.log(newArrFn(arr))
1.2 性能优化
当我以为自己的方法很好的时候,看到一篇文章分析上面的写法性能上是很差的
所以我们分析一下他的做法
说实话,这种做法我刚开始肯定是做不出来的
但是我发现一种学习方法,那就是一个你不会的方法
你可以讲给别人听,这样可以让我们印象深刻
原因是,咱们讲给别人听,需要自己整理思路
还要手敲一遍,等,所以大家学习建议给别人讲
function arrayToTree(items) {
const result = [];
const itemMap = {};
for (const item of items) {
itemMap[item.id] = {...item, children: []}
}
for (const item of items) {
const id = item.id;
const pid = item.p_id;
const treeItem = itemMap[id];
if (pid === 0) {
result.push(treeItem);
} else {
if (!itemMap[pid]) {
itemMap[pid] = {
children: [],
}
}
itemMap[pid].children.push(treeItem)
}
}
return result;
}
function arrayToTree(items) {
const result = []; // 存放结果集
const itemMap = {}; //
for (const item of items) {
const id = item.id;
const pid = item.p_id;
if (!itemMap[id]) {
itemMap[id] = {
children: [],
}
}
itemMap[id] = {
...item,
children: itemMap[id]['children']
}
const treeItem = itemMap[id];
if (pid === 0) {
result.push(treeItem);
} else {
if (!itemMap[pid]) {
itemMap[pid] = {
children: [],
}
}
itemMap[pid].children.push(treeItem)
}
}
return result;
}
2.1 二维转一维数组
const arr = [[1, 2], [3, 4], [5, 6], 7]
// function newArrFn(arr) {
// return arr.reduce((acc, cur) => {
// // return acc.concat(cur)
// acc.concat(cur) // 错误
// return acc // 错误
// }, [])
// }
function newArrFn(arr) {
return arr.reduce((acc, cur) => acc.concat(cur), [])
}
console.log(newArrFn(arr))
2.2 多维转一维数组
const arr = [[1, 2, [1, 2, [1, 2]]], [3, 4], [5, 6], 7]
// function newArrFn(arr) {
// return arr.reduce((acc, cur) => {
// if (Array.isArray(cur)) {
// return acc.concat(newArrFn(cur))
// } else {
// return acc.concat(cur)
// }
// }, [])
// }
function newArrFn(arr) {
return arr.reduce((acc, cur) => acc.concat(Array.isArray(cur) ? newArrFn(cur) : cur), [])
}
console.log(newArrFn(arr))
2.3 多维转一维数组(内含对象)
const arr = [
{
id: 1,
p_id: 0,
name: '首页',
children: [
{
id: 4,
p_id: 1,
name: '权限管理',
children: [
{
id: 6,
p_id: 4,
name: '角色列表',
children: [
{
id: 5,
p_id: 6,
name: '管理员列表',
},
],
},
],
},
],
},
{
id: 2,
p_id: 0,
name: '菜单管理'
},
{
id: 3,
p_id: 0,
name: '菜单列表'
}
]
// function newArrFn(arr) {
// return arr.reduce((acc, cur) => {
// if (Array.isArray(cur.children)) {
// // acc = acc.concat(cur)
// // return acc.concat(newArrFn(cur.children))
// return acc.concat(cur, newArrFn(cur.children))
// } else {
// return acc.concat(cur)
// }
// }, [])
// }
// function newArrFn(arr) {
// return arr.reduce((acc, cur) => acc.concat(cur, Array.isArray(cur.children) ? // newArrFn(cur.children) : []), [])
// }
// 得到的新数组的对象中含有children属性,需要删除
function newArrFn(arr) {
return arr.reduce((acc, cur) => {
if (Array.isArray(cur.children)) {
const copyCur = { ...cur }
delete copyCur.children
return acc.concat(copyCur, newArrFn(cur.children))
} else {
return acc.concat(cur)
}
}, [])
}
console.log(newArrFn(arr))