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

JavaScript中从对象数组生成通用n级嵌套层级结构的实现方案

扁平对象数组转n级层级结构的通用解决方案

问题背景

给定如下扁平结构的对象数组:

[
  {"company": "Google", "country": "USA", "employee": "John"},
  {"company": "Amazon", "country": "UK", "employee": "Arya"},
  {"company": "Google", "country": "KSA", "employee": "Cersi"},
  {"company": "Amazon", "country": "USA", "employee": "Tyrion"},
  {"company": "Amazon", "country": "USA", "employee": "Daenarys"},
  {"company": "Google", "country": "KSA", "employee": "Dothrokhi"}
]

需要将其转换为指定的层级结构:

{
  "company": [
    {
      "company": "Amazon",
      "country": [
        {
          "country": "UK",
          "employee": [
            "Arya"
          ]
        },
        {
          "country": "USA",
          "employee": [
            "Tyrion",
            "Daenarys"
          ]
        }
      ]
    },
    {
      "company": "Google",
      "country": [
        {
          "country": "KSA",
          "employee": [
            "Cersi",
            "Dothrokhi"
          ]
        },
        {
          "country": "USA",
          "employee": [
            "John"
          ]
        }
      ]
    }
  ]
}

核心疑问

  • 使用array.reduce()或array.map()哪种方案更优?
  • 是否有其他更合适的实现方法?
  • 如何实现通用n级树形结构(支持level1->level2->…->leveln的层级转换),同时处理重复数据?

现有非通用实现(仅支持3级)

以下代码仅能处理示例中的3级结构,无法适配任意层级:

const data = [{
    company: "Google",
    country: "USA",
    employee: "John"
  },
  {
    company: "Amazon",
    country: "UK",
    employee: "Arya"
  },
  {
    company: "Google",
    country: "KSA",
    employee: "Cersi"
  },
  {
    company: "Amazon",
    country: "USA",
    employee: "Tyrion"
  },
  {
    company: "Amazon",
    country: "USA",
    employee: "Daenarys"
  },
  {
    company: "Google",
    country: "KSA",
    employee: "Dothrokhi"
  }
];

let res = Object.entries(
    data.reduce((result, {
      company,
      country,
      employee
    }) => {
      const groupedSubtypeList = (result[company] ??= []);

      if (country !== null) {
        groupedSubtypeList.push({
          country,
          employee
        });
      }
      return result;
    }, {})
  )
  .map(([company, countries]) => {
    const companyItem = {
      company: company
    };
    if (countries.length >= 1) {
      let temp = Object.entries(
        countries.reduce((result, {
          country,
          employee
        }) => {
          const groupedSubtypeList = (result[country] ??= []);

          if (employee !== null) {
            groupedSubtypeList.push(employee);
          }
          return result;
        }, {})
      ).map(([country, employee]) => {
        const countryItem = {
          country: country
        };
        if (employee.length >= 1) {
          countryItem.employee = employee.map((employee) => employee);
        }
        return countryItem;
      });
      companyItem.country = temp;
    }
    return companyItem;
  });

console.log(res);

通用解决方案实现

方案选择:优先使用reduce

map仅能做一对一的转换,无法处理聚合分组逻辑;而reduce天生适合数据聚合、分组和层级构建,是这类场景的最优选择。我们可以基于reduce实现递归式的通用层级构建函数。

通用n级层级转换函数

以下函数支持传入任意层级的字段列表(如['company', 'country', 'employee']),自动构建对应的层级结构:

function buildHierarchy(data, levels) {
  // 递归构建层级的核心函数
  function groupByLevel(items, levelIndex) {
    if (levelIndex >= levels.length - 1) {
      // 最后一级,返回去重后的数值数组
      return [...new Set(items.map(item => item[levels[levelIndex]]))];
    }

    const currentLevel = levels[levelIndex];
    const nextLevel = levels[levelIndex + 1];

    // 使用reduce分组当前层级的所有值
    const grouped = items.reduce((acc, item) => {
      const key = item[currentLevel];
      if (!acc[key]) {
        acc[key] = [];
      }
      acc[key].push(item);
      return acc;
    }, {});

    // 转换为目标格式:[{ [currentLevel]: key, [nextLevel]: 子层级数据 }]
    return Object.entries(grouped).map(([key, childItems]) => ({
      [currentLevel]: key,
      [nextLevel]: groupByLevel(childItems, levelIndex + 1)
    }));
  }

  // 最外层包装:{ [第一级字段名]: 层级数据 }
  const rootLevel = levels[0];
  return {
    [rootLevel]: groupByLevel(data, 0)
  };
}

// 使用示例
const data = [
  {"company": "Google", "country": "USA", "employee": "John"},
  {"company": "Amazon", "country": "UK", "employee": "Arya"},
  {"company": "Google", "country": "KSA", "employee": "Cersi"},
  {"company": "Amazon", "country": "USA", "employee": "Tyrion"},
  {"company": "Amazon", "country": "USA", "employee": "Daenarys"},
  {"company": "Google", "country": "KSA", "employee": "Dothrokhi"}
];

// 传入层级字段列表
const hierarchy = buildHierarchy(data, ['company', 'country', 'employee']);
console.log(JSON.stringify(hierarchy, null, 2));

代码说明

  1. 递归分组:通过groupByLevel递归处理每一层级,直到最后一级时返回去重后的数值数组。
  2. 自动适配层级:只需传入不同的层级字段列表(如['department', 'team', 'role', 'name']),即可生成对应n级结构。
  3. 去重处理:最后一级使用new Set自动去重,若中间层级需要去重,可在分组时增加判断逻辑。
  4. 灵活扩展:如果需要调整层级格式(如修改子节点字段名),只需修改递归返回的对象结构即可。

其他可选方案

  • 迭代式实现:对于层级极深的场景,递归可能存在栈溢出风险,可将递归改为循环迭代的方式,逐个层级构建。
  • 第三方工具函数:如lodash.groupBy可以简化单层级分组,但多层级仍需自行组合逻辑,不如自定义函数灵活。

内容的提问来源于stack exchange,提问作者JEEVAN GEORGE ANTONY

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 21:15:33