You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 09:24:00