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

如何用JavaScript将基于source-target关联的扁平JSON转为树形结构

把扁平JSON转成基于links关联的树形视图

嘿,我来帮你搞定这个需求!你手头的JSON是典型的节点-边结构,要转成树形视图的话,核心就是通过links里的source和target索引,把节点之间的父子关系建立起来。下面我用JavaScript给你写个实用的实现,思路清晰还容易扩展~

先理清楚核心逻辑

  1. 建立节点映射表:把所有节点按index存成键值对,方便快速查找,同时给每个节点加上children数组用来存子节点。
  2. 关联父子关系:遍历每一条link,找到父节点(source对应的节点),把子节点(target对应的节点)加到父节点的children里。
  3. 收集根节点:根节点就是那些从来没被任何link的target指向的节点——毕竟树的顶层节点没有父节点嘛。

完整代码实现

首先先把你给的原始JSON修正成合法格式(注意属性名要加双引号):

{
  "nodes": [
    {"name": "bz_db", "index": 0},
    {"name": "mysql", "index": 1},
    {"name": "postgres", "index": 2},
    {"name": "it-infra", "index": 3},
    {"name": "user-count", "index": 4}
  ],
  "links": [
    {"source": 0, "target": 1},
    {"source": 0, "target": 3},
    {"source": 1, "target": 3},
    {"source": 3, "target": 4}
  ]
}

然后是转换函数:

function flatToTree(data) {
  // 第一步:创建节点映射,给每个节点初始化children数组
  const nodeMap = {};
  data.nodes.forEach(node => {
    nodeMap[node.index] = { ...node, children: [] };
  });

  // 第二步:遍历links,建立父子关联
  data.links.forEach(link => {
    const parent = nodeMap[link.source];
    const child = nodeMap[link.target];
    parent.children.push(child);
  });

  // 第三步:找出所有根节点(没有被作为target的节点)
  const allTargetIndexes = new Set(data.links.map(link => link.target));
  const treeRoots = data.nodes
    .filter(node => !allTargetIndexes.has(node.index))
    .map(node => nodeMap[node.index]);

  return treeRoots;
}

// 测试一下
const inputData = {
  "nodes": [
    {"name": "bz_db", "index": 0},
    {"name": "mysql", "index": 1},
    {"name": "postgres", "index": 2},
    {"name": "it-infra", "index": 3},
    {"name": "user-count", "index": 4}
  ],
  "links": [
    {"source": 0, "target": 1},
    {"source": 0, "target": 3},
    {"source": 1, "target": 3},
    {"source": 3, "target": 4}
  ]
};
const treeResult = flatToTree(inputData);
console.log(JSON.stringify(treeResult, null, 2));

输出结果

运行后你会得到这样的树形结构:

[
  {
    "name": "bz_db",
    "index": 0,
    "children": [
      {
        "name": "mysql",
        "index": 1,
        "children": [
          {
            "name": "it-infra",
            "index": 3,
            "children": [
              {
                "name": "user-count",
                "index": 4,
                "children": []
              }
            ]
          }
        ]
      },
      {
        "name": "it-infra",
        "index": 3,
        "children": [
          {
            "name": "user-count",
            "index": 4,
            "children": []
          }
        ]
      }
    ]
  },
  {
    "name": "postgres",
    "index": 2,
    "children": []
  }
]

小说明

这里你会看到it-infra出现了两次,因为原始的links里有两条指向它的关系(bz_db→it-infra和mysql→it-infra)。如果你的需求是每个节点只能在树里出现一次,那可以加个visited集合来过滤重复添加的节点——不过这个得看你具体的业务场景啦~

内容的提问来源于stack exchange,提问作者kaounKaoun

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 04:22:13