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

如何将含ID与子节点引用的对象数组转换为嵌套树形结构?

如何将扁平nodes数组转换为嵌套树形结构?

问题背景

你有一组扁平的节点数据,需要将其转换为嵌套的树形结构,同时希望适配任意数量的节点和任意深度的层级。

原始输入数据

const nodes = [ 
  { name: "Ben", id: 1, next: [2, 3], depth: 0 }, 
  { name: "Mike", id: 2, next: [4, 5], depth: 1 }, 
  { name: "Jen", id: 3, next: [6], depth: 1 }, 
  { name: "Sue", id: 4, next: [], depth: 2 }, 
  { name: "Jeff", id: 5, next: [], depth: 2 }, 
  { name: "Bob", id: 6, next: [], depth: 3 } 
];

目标树形结构

const root = { 
  name: "Ben", 
  children: [ 
    { name: "Mike", children: [ { name: "Sue" }, { name: "Jeff" } ] }, 
    { name: "Jen", children: [ { name: "Bob" } ] } 
  ] 
};

已实现的部分逻辑

你已经完成了根节点第一层子节点的添加,但不知道如何处理更深层级的子节点:

const root = { name: nodes[0].name }; 
root.children = []; 
nodes[0].next.map(function (next) { 
  nodes.map((node, i) => { 
    if (next === node.id) { 
      root.children.push({name: nodes[i].name}) 
    } 
  }) 
});

你的疑问

如何动态创建children数组并添加正确的属性,以适配任意数量的节点和任意深度的树形结构?


解决方案

要处理任意深度的树形结构,我们可以通过建立节点映射表+批量关联子节点的方式来实现,效率更高且能适配所有情况。

步骤1:建立ID到节点的映射表

首先把所有节点存入一个以id为键的对象中,这样可以快速通过id找到对应的节点,避免重复遍历数组:

const nodeMap = {};
nodes.forEach(node => {
  // 先创建每个节点的基础结构(只保留name)
  nodeMap[node.id] = { name: node.name };
});

步骤2:批量关联子节点

遍历每个原始节点,根据它的next数组,把对应的子节点添加到映射表中节点的children属性里:

nodes.forEach(node => {
  // 如果当前节点有子节点ID,就生成对应的children数组
  if (node.next.length > 0) {
    nodeMap[node.id].children = node.next.map(childId => nodeMap[childId]);
  }
});

步骤3:获取根节点

最后从映射表中取出根节点(这里我们用nodes[0].id,你也可以根据depth: 0来筛选):

const root = nodeMap[nodes[0].id];

完整代码示例

const nodes = [ 
  { name: "Ben", id: 1, next: [2, 3], depth: 0 }, 
  { name: "Mike", id: 2, next: [4, 5], depth: 1 }, 
  { name: "Jen", id: 3, next: [6], depth: 1 }, 
  { name: "Sue", id: 4, next: [], depth: 2 }, 
  { name: "Jeff", id: 5, next: [], depth: 2 }, 
  { name: "Bob", id: 6, next: [], depth: 3 } 
];

// 1. 建立节点映射表
const nodeMap = {};
nodes.forEach(node => {
  nodeMap[node.id] = { name: node.name };
});

// 2. 关联子节点
nodes.forEach(node => {
  if (node.next.length) {
    nodeMap[node.id].children = node.next.map(id => nodeMap[id]);
  }
});

// 3. 获取根节点
const root = nodeMap[nodes[0].id];
console.log(root);

方案优势

  • 高效性:时间复杂度为O(n),相比嵌套遍历的O(n²),在节点数量多时性能提升明显。
  • 通用性:不管树形结构有多深,只要next数组正确指向子节点ID,就能自动构建对应的层级。
  • 灵活性:适配任意数量的节点,无需修改代码结构。

备选:递归写法

如果你更喜欢直观的递归逻辑,也可以用递归函数逐个构建子树:

function buildTree(nodeId) {
  // 找到当前ID对应的原始节点
  const currentNode = nodes.find(n => n.id === nodeId);
  // 创建树形节点
  const treeNode = { name: currentNode.name };
  // 如果有子节点,递归构建
  if (currentNode.next.length > 0) {
    treeNode.children = currentNode.next.map(childId => buildTree(childId));
  }
  return treeNode;
}

// 从根节点ID开始构建
const root = buildTree(nodes[0].id);

注意:这种写法中find方法会遍历数组,当节点数量较多时,性能不如映射表方案。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:11:55