JS如何将扁平任务子任务数组转换为未知层级递归树形结构
问题分析
你之前的代码核心问题有两个:
- 字段名不匹配,原始数据的父级字段是
task、子级是sub-task,你代码里用的parentGroup和groupName完全对应不上 - 递归逻辑只遍历了最顶层的根节点数组,没有递归查找深层
children里的父节点,所以超过两层的嵌套就匹配不到
实现方案
推荐用哈希表存所有节点引用的方式实现,比纯递归遍历效率高很多,嵌套层级再多也能处理:
// 原始数据 const rawData = [ {"sub-task":"abc","task":"alpha1"}, {"sub-task":"def","task":"alpha1"}, {"sub-task":"ijkl","task":"proto"}, {"sub-task":"mno","task":"def"}, {"sub-task":"qrs","task":"proto"}, {"sub-task":"asdf","task":"mno"} ]; const nodeMap = {}; // 存储所有节点的引用,key为节点name const subTaskSet = new Set(); // 存储所有当过子节点的name,用来筛选根节点 // 第一步:先把所有节点都存到映射表,同时建立父子关系 rawData.forEach(item => { const parentName = item['task']; const childName = item['sub-task']; // 父节点不存在就新建 if (!nodeMap[parentName]) { nodeMap[parentName] = { name: parentName, children: [] }; } // 子节点不存在就新建 if (!nodeMap[childName]) { nodeMap[childName] = { name: childName, children: [] }; } // 把子节点加到父节点的children里 nodeMap[parentName].children.push(nodeMap[childName]); // 标记该节点是子节点,不可能是根 subTaskSet.add(childName); }); // 第二步:筛选所有从来没当过子节点的节点作为根节点,就是最终结果 const result = Object.values(nodeMap).filter(node => !subTaskSet.has(node.name));
如果不需要保留无子节点的空children属性,可以加一步处理:
// 可选:去掉空children属性 function removeEmptyChildren(node) { if (node.children.length === 0) { delete node.children; } else { node.children.forEach(removeEmptyChildren); } } result.forEach(removeEmptyChildren);
运行后输出的结构就和你要求的完全一致。
内容的提问来源于stack exchange,提问作者Lisa
相关产品推荐
相关产品推荐

