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

如何将含parent属性的数组转换为含children属性的层级数组?

扁平数组转层级结构:问题分析与优化方案

需求背景

你需要把一个扁平的英雄数组 currentModel 转换成带有层级嵌套结构的 requiredModel,其中每个节点的 children 数组包含其直接子节点。

原数组与目标结构

原扁平数组:

var currentModel = [
  {id: 'Iron Man (CPC Avengers)', label: 'Iron Man', unit: 'CPC Avengers', level: '2', parent: '', children: []},
  {id: 'Thor (Avengers Core Asgard)', label: 'Thor', unit: 'Avengers Core Asgard', level: '3', parent: 'Iron Man', children: []},
  {id: 'Loki (Avengers Asgard)', label: 'Loki', unit: 'Avengers Asgard', level: '4', parent: 'Thor', children: []},
  {id: 'Hela (Avengers Asgard)', label: 'Hela', unit: 'Avengers Asgard', level: '4', parent: 'Thor', children: []},
  {id: 'Groot (Guardians of Galaxy)', label: 'Groot', unit: 'Guardians of Galaxy', level: '5', parent: 'Loki', children: []},
  {id: 'Captain America (Avengers Core Earth)', label: 'Captain America', unit: 'Avengers Core Earth', level: '3', parent: 'Iron Man', children: []},
  {id: 'Black Widow (Avengers Earth)', label: 'Black Widow', unit: 'Avengers Earth', level: '4', parent: 'Captain America', children: []},
  {id: 'Hulk (Avengers Earth)', label: 'Hulk', unit: 'Avengers Earth', level: '4', parent: 'Captain America', children: []}
];

目标层级结构:

var requiredModel = [
  {
    id: 'Iron Man (CPC Avengers)', label: 'Iron Man', unit: 'CPC Avengers', level: '2', parent: '', children: [
      {
        id: 'Thor (Avengers Core Asgard)', label: 'Thor', unit: 'Avengers Core Asgard', level: '3', parent: 'Iron Man', children: [
          {
            id: 'Loki (Avengers Asgard)', label: 'Loki', unit: 'Avengers Asgard', level: '4', parent: 'Thor', children: [
              { id: 'Groot (Guardians of Galaxy)', label: 'Groot', unit: 'Guardians of Galaxy', level: '5', parent: 'Loki', children: []}
            ]
          },
          {id: 'Hela (Avengers Asgard)', label: 'Hela', unit: 'Avengers Asgard', level: '4', parent: 'Thor', children: []}
        ]
      },
      {
        id: 'Captain America (Avengers Core Earth)', label: 'Captain America', unit: 'Avengers Core Earth', level: '3', parent: 'Iron Man', children: [
          { id: 'Black Widow (Avengers Earth)', label: 'Black Widow', unit: 'Avengers Earth', level: '4', parent: 'Captain America', children:[]},
          { id: 'Hulk (Avengers Earth)', label: 'Hulk', unit: 'Avengers Earth', level: '4', parent: 'Captain America', children: []}
        ]
      }
    ]
  }
];

你的尝试与问题

你尝试先按 level 拆分不同层级的数组,再通过嵌套循环将子节点添加到父节点的 children 中,但运行时浏览器崩溃了。问题出在这段循环代码里:

for (var i = 0; i < currentModelLvl4.length; i++) { 
  var currentModelItem4 = currentModelLvl4[i]; 
  for (var j = 0; j < currentModelLvl5.length; j++) { 
    // 这里写错了!应该是 currentModelLvl5[j],不是 currentModelLvl4[j]
    var currentModelItem5 = currentModelLvl4[j]; 
    if (currentModelItem4.label === currentModelItem5.parent) { 
      currentModelItem4.children.push(currentModelItem5); 
    } 
  } 
}

核心问题分析

  1. 变量赋值错误:currentModelItem5 被错误赋值为 currentModelLvl4[j],导致循环逻辑完全混乱,甚至可能出现无限循环(如果数组长度变化的话),直接引发浏览器崩溃。
  2. 效率低下:即使修正了变量,嵌套循环的时间复杂度是 O(n²),当数组数据量较大时,性能会急剧下降,同样可能导致浏览器卡顿或崩溃。
  3. 层级依赖限制:按 level 拆分的方式不够灵活,如果后续新增了 level:6 的节点,你需要手动添加新的拆分和循环逻辑,扩展性差。

更优的实现方案

我们可以用**哈希映射(对象)**来快速定位父节点,只需要遍历数组两次(甚至一次)就能完成转换,时间复杂度降到 O(n),同时逻辑更灵活,支持任意层级的嵌套。

实现代码

function buildHierarchicalModel(flatArray) {
  // 1. 创建映射表:用节点的 label 作为键,存储对应节点的引用
  const nodeMap = {};
  const rootNodes = [];

  // 2. 第一次遍历:填充映射表,并收集根节点(parent为空的节点)
  flatArray.forEach(node => {
    // 确保 children 数组存在(避免原数组中 children 未初始化的情况)
    node.children = node.children || [];
    nodeMap[node.label] = node;
    
    if (node.parent === '') {
      rootNodes.push(node);
    }
  });

  // 3. 第二次遍历:将每个节点添加到其父节点的 children 数组中
  flatArray.forEach(node => {
    const parentNode = nodeMap[node.parent];
    // 如果父节点存在且当前节点不是根节点
    if (parentNode && node.parent !== '') {
      parentNode.children.push(node);
    }
  });

  return rootNodes;
}

// 使用示例
var requiredModel = buildHierarchicalModel(currentModel);
console.log(requiredModel);

方案优势

  • 高效:仅需两次遍历,时间复杂度 O(n),数据量大时性能优势明显。
  • 灵活:无需关心层级数量,新增任意 level 的节点都能自动处理。
  • 健壮:自动处理 children 未初始化的情况,避免报错。

额外说明

如果你的 parent 字段对应的是节点的 id 而不是 label,只需要把映射表的键从 node.label 改成 node.id,同时判断条件里的 node.parent 对应查找 nodeMap[node.parent] 即可,逻辑完全通用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:37:57