一.列表结构转换为树形结构
1.递归
ini
复制代码
/*
@param list 需要处理的数组
@param parentId 父节点ID
*/
function listToTree(list, parentId = null) {
const tree = [];
for (const item of list) {
if (item.parentId === parentId) {
const children = listToTree(list, item.id);
if (children.length > 0) {
item.children = children;
}
tree.push(item);
}
}
return tree;
}
2.哈希表(对象/Map)的方法(推荐)
ini
复制代码
function listToTree(items, idKey = 'id', parentKey = 'parentId', childrenKey = 'children') {
const map = {};
const roots = [];
// 第一遍遍历:创建哈希映射
for (const item of items) {
map[item[idKey]] = { ...item, [childrenKey]: [] };
}
// 第二遍遍历:建立父子关系
for (const item of items) {
const parentId = item[parentKey];
if (parentId !== null && parentId !== undefined && map[parentId]) {
map[parentId][childrenKey].push(map[item[idKey]]);
} else {
roots.push(map[item[idKey]]);
}
}
return roots;
}
3.双循环方法
ini
复制代码
function listToTree(items, idKey = 'id', parentKey = 'parentId', childrenKey = 'children') {
const roots = [];
for (const item of items) {
if (!item[parentKey]) {
roots.push({ ...item, [childrenKey]: [] });
} else {
const parent = items.find(p => p[idKey] === item[parentKey]);
if (parent) {
if (!parent[childrenKey]) parent[childrenKey] = [];
parent[childrenKey].push({ ...item, [childrenKey]: [] });
}
}
}
return roots;
}
4.使用Map和一次遍历
ini
复制代码
function listToTree(items, idKey = 'id', parentKey = 'parentId', childrenKey = 'children') {
const map = new Map();
const roots = [];
items.forEach(item => {
const node = { ...item, [childrenKey]: [] };
map.set(node[idKey], node);
if (node[parentKey] && map.has(node[parentKey])) {
map.get(node[parentKey])[childrenKey].push(node);
} else if (!node[parentKey]) {
roots.push(node);
}
});
return roots;
}
方法 |
时间复杂度 |
适合场景 |
优势 |
劣势 |
哈希表(对象)两次遍历 |
O(n) |
大数据量、通用场景 |
最高效,两次线性遍历 |
需要额外存储哈希表 |
Map 一次遍历 |
O(n) |
大数据量、ES6 环境 |
只需一次遍历,代码更简洁 |
依赖 Map ,旧浏览器需 polyfill |
双循环嵌套 |
O(n²) |
小数据量(<1000 条) |
实现简单 |
数据量大时性能急剧下降 |
递归 |
/ |
小数据量(<1000 条) |
实现简单 |
数据量大时性能急剧下降 |
树形结构转列表
1.递归(小批量数据)
scss
复制代码
function treeToList(tree, list = [], parentId = null) {
for (const node of tree) {
const { children, ...rest } = node;
list.push({ ...rest, parentId });
if (children && children.length > 0) {
treeToList(children, list, node.id);
}
}
return list;
}
2.## 使用堆栈的非递归(大批量数据)
c
复制代码
function treeToListStack(tree) {
const list = [];
const stack = [...tree.map(node => ({ node, parentId: null }))];
while (stack.length > 0) {
const { node, parentId } = stack.pop();
const { children, ...rest } = node;
list.push({ ...rest, parentId });
if (children && children.length > 0) {
stack.push(...children.map(child => ({
node: child,
parentId: node.id
})).reverse());
}
}
return list;
}