返回
数组转Tree别再“卷”了,直接上这几招就能秒杀面试官
前端
2023-09-08 12:48:55
前言
最近在掘金上看到了不少关于扁平数组转树形结构的文章,都是各式各样,实际工作中,我也有过类似的场景,只不过更奇葩一点 ~
背景
我是做一个可视化开发平台,基于拖拉拽快速实现可视化页面(PC, 手机网页)。
我们的系统中,界面中的所有元素,比如按钮、文本框、图片等,都是以树形结构存储的,而前端工程师传入的数据,往往都是扁平的数组。
所以,在渲染界面之前,我们需要把这些扁平的数组转换成树形结构。
难点
由于历史原因,我们的前端工程师使用的是一种比较奇葩的数据结构,这种数据结构的特点是:
- 每个节点都有一个唯一的id
- 每个节点都有一个parent_id
- 每个节点都有一个children属性,表示该节点的子节点
也就是说,我们的数据结构是这样的:
[
{
"id": 1,
"parent_id": null,
"children": [
{
"id": 2,
"parent_id": 1,
"children": []
},
{
"id": 3,
"parent_id": 1,
"children": []
}
]
},
{
"id": 4,
"parent_id": null,
"children": [
{
"id": 5,
"parent_id": 4,
"children": []
},
{
"id": 6,
"parent_id": 4,
"children": []
}
]
}
]
这种数据结构的特点是,每个节点都包含了其所有子节点的信息。
这样的数据结构,在某些场景下是很有用的,比如在做可视化的时候,我们可以直接把这个数据结构渲染成树形结构。
但是,在某些场景下,这种数据结构也是很麻烦的,比如在做数据统计的时候,我们需要把所有节点的数据都统计一遍,而这种数据结构,会导致我们重复统计很多次。
解决方案
为了解决这个问题,我们可以把这种奇葩的数据结构转换成一种更常见的树形结构。
树形结构的特点是:
- 每个节点都有一个唯一的id
- 每个节点都有一个parent_id
- 每个节点都有一个children属性,表示该节点的子节点
也就是说,我们要把这种奇葩的数据结构转换成这样的数据结构:
{
"id": 1,
"parent_id": null,
"children": [
{
"id": 2,
"parent_id": 1,
"children": []
},
{
"id": 3,
"parent_id": 1,
"children": []
}
]
}
这种数据结构的特点是,每个节点只包含了其直接子节点的信息。
这样的数据结构,在做数据统计的时候,可以大大减少重复统计的次数。
实现方案
要把奇葩的数据结构转换成树形结构,我们可以使用递归的方法。
递归的方法很简单,就是把问题分解成更小的子问题,然后逐个解决。
在我们的场景中,我们可以把问题分解成以下几个子问题:
- 找到根节点
- 把根节点的子节点转换成树形结构
- 把根节点的子节点的子节点转换成树形结构
以此类推,直到所有的节点都转换成树形结构。
function convert(data) {
// 找到根节点
const root = data.find(item => item.parent_id === null);
// 把根节点的子节点转换成树形结构
root.children = convertChildren(root.id, data);
return root;
}
function convertChildren(parent_id, data) {
// 找到该父节点的所有子节点
const children = data.filter(item => item.parent_id === parent_id);
// 把这些子节点转换成树形结构
children.forEach(child => {
child.children = convertChildren(child.id, data);
});
return children;
}
总结
以上就是把奇葩的数据结构转换成树形结构的解决方案。
这个解决方案很简单,但是很有效。
如果你也遇到了类似的问题,不妨试试这个解决方案。