首页 > web前端 > js教程 > 正文

将扁平JSON数据转换为带层级的嵌套结构

碧海醫心
发布: 2025-10-09 13:58:18
原创
785人浏览过

将扁平json数据转换为带层级的嵌套结构

本教程详细介绍了如何将包含层级(level)信息的扁平JSON数组转换为具有父子关系的嵌套JSON结构。通过迭代数据并利用映射表追踪各层级节点,我们可以高效地构建出复杂的树状结构,适用于动态菜单、文件系统表示等场景,确保输出结构清晰、逻辑严谨。

1. 场景概述与问题定义

前端开发或数据处理中,我们经常会遇到需要将线性的、扁平化的数据列表转换成具有层级关系的树状结构。例如,一个网站的导航菜单、文件目录结构或评论回复链等。这些数据通常以数组形式存储,其中每个元素包含一个标识其层级的属性(如 level)。

我们的目标是将以下结构的扁平JSON数据:

const content = [
  { title: "Item 1", metaData: { "level": 1, "desc": "Some Desc 1", "displayOnOverview": true }},
  { title: "Item 2", metaData: { "level": 2, "desc": "Some Desc 2", "displayOnOverview": true }},
  { title: "Item 3", metaData: { "level": 2, "desc": "Some Desc 3", "displayOnOverview": false }},
  { title: "Item 4", metaData: { "level": 3, "desc": "Some Desc 4", "displayOnOverview": true }},
  { title: "Item 5", metaData: { "level": 1, "desc": "Some Desc 5", "displayOnOverview": true }}
];
登录后复制

转换为以下具有 subNav 属性的嵌套结构:

[
  {
    "title": "Item 1",
    "metaData": {
      "desc": "Some Desc 1",
      "displayOnOverview": true
    },
    "subNav": [
      {
        "title": "Item 2",
        "metaData": {
          "desc": "Some Desc 2",
          "displayOnOverview": true
        }
      },
      {
        "title": "Item 3",
        "metaData": {
          "desc": "Some Desc 3",
          "displayOnOverview": false
        },
        "subNav": [
          {
            "title": "Item 4",
            "metaData": {
              "desc": "Some Desc 4",
              "displayOnOverview": true
            }
          }
        ]
      }
    ]
  },
  {
    "title": "Item 5",
    "metaData": {
      "desc": "Some Desc 5",
      "displayOnOverview": true
    }
  }
]
登录后复制

核心挑战在于如何根据 level 属性正确地识别父子关系,并将子节点动态地添加到其父节点的 subNav 数组中。

2. 核心转换逻辑与算法设计

为了高效地构建嵌套结构,我们需要一种机制来追踪当前处理的节点及其潜在的父节点。这里介绍一种基于迭代和映射表的解决方案。

算法思路:

  1. 初始化:

    • 创建一个空数组 topLevelItems 用于存放所有 level 为 1 的顶级节点。
    • 创建一个映射表 itemMap,其键为层级(level),值为该层级最近处理过的节点对象。这个映射表是实现动态父子链接的关键。
  2. 迭代处理: 遍历输入的扁平数据数组 data 中的每一个 item。

    Find JSON Path Online
    Find JSON Path Online

    Easily find JSON paths within JSON objects using our intuitive Json Path Finder

    Find JSON Path Online 30
    查看详情 Find JSON Path Online
  3. 节点构建: 对于每个 item,提取其 title 和 metaData。需要注意的是,最终输出的 metaData 不应包含 level 属性,因为 level 仅用于结构构建,而非最终数据负载。因此,我们创建一个新的 newItem 对象,其中 metaData 只包含除 level 之外的其他属性。

  4. 判断层级并连接:

    • 顶级节点 (level === 1): 如果当前 item 的 level 为 1,它是一个顶级节点。直接将其 newItem 添加到 topLevelItems 数组中。
    • 子节点 (level > 1): 如果当前 item 的 level 大于 1,它是一个子节点。
      • 计算其父节点的层级 parentLevel = metaData.level - 1。
      • 从 itemMap 中获取 parentLevel 对应的父节点 parentItem。
      • 如果 parentItem 尚无 subNav 数组,则为其创建一个空数组。
      • 将当前 newItem 添加到 parentItem.subNav 数组中。
  5. 更新映射表: 无论当前 item 是顶级节点还是子节点,都需要将其 newItem 存储到 itemMap 中,键为 metaData.level。这样,当前 newItem 就成为了后续更高层级节点的潜在父节点。

  6. 返回结果: 遍历结束后,topLevelItems 数组将包含完整的嵌套结构。

3. 示例代码实现

以下是使用 JavaScript 实现上述算法的完整代码:

const content = [
  { title: "Item 1", metaData: { "level": 1, "desc": "Some Desc 1", "displayOnOverview": true }},
  { title: "Item 2", metaData: { "level": 2, "desc": "Some Desc 2", "displayOnOverview": true }},
  { title: "Item 3", metaData: { "level": 2, "desc": "Some Desc 3", "displayOnOverview": false }},
  { title: "Item 4", metaData: { "level": 3, "desc": "Some Desc 4", "displayOnOverview": true }},
  { title: "Item 5", metaData: { "level": 1, "desc": "Some Desc 5", "displayOnOverview": true }}
];

/**
 * 将扁平JSON数组转换为带有层级关系的嵌套结构。
 *
 * @param {Array<Object>} data 包含 level 属性的扁平数据数组。
 * @returns {Array<Object>} 转换后的嵌套JSON数组。
 */
function buildNestedStructure(data) {
  const topLevelItems = []; // 存储所有 level 1 的顶级节点
  const itemMap = {};       // 映射表,键为层级,值为该层级最近处理过的节点

  for (const item of data) {
    const { title, metaData } = item;
    // 解构 metaData,将 level 属性分离,其余属性放入 restMetaData
    const { level, ...restMetaData } = metaData;

    // 创建新的节点对象,其 metaData 不包含 level 属性
    const newItem = { title, metaData: restMetaData };

    if (level === 1) {
      // 如果是顶级节点,直接添加到 topLevelItems 数组
      topLevelItems.push(newItem);
    } else {
      // 如果是子节点,找到其父节点的层级
      const parentLevel = level - 1;
      const parentItem = itemMap[parentLevel]; // 从映射表中获取父节点

      // 检查父节点是否存在,并确保其有 subNav 数组
      if (parentItem) {
        if (!parentItem.subNav) {
          parentItem.subNav = [];
        }
        // 将当前新节点添加到父节点的 subNav 数组中
        parentItem.subNav.push(newItem);
      } else {
        // 如果找不到父节点,这可能意味着数据不完整或顺序有误
        // 在实际应用中,可以根据需求选择抛出错误或跳过
        console.warn(`Warning: Parent item for level ${level} not found for item: ${title}`);
      }
    }

    // 更新 itemMap,将当前新节点作为其层级下的最新节点,供后续子节点查找
    itemMap[level] = newItem;
  }

  return topLevelItems;
}

const output = buildNestedStructure(content);
console.log(JSON.stringify(output, null, 2));
登录后复制

4. 代码解析与注意事项

  • topLevelItems 数组: 顾名思义,它负责收集所有 level: 1 的根节点。最终函数返回的就是这个数组。
  • itemMap 对象: 这是实现动态父子关系的关键。它存储了每个层级(level)最近处理过的节点引用。当处理一个 level: N 的节点时,它会查找 itemMap[N-1] 来获取其父节点。这种方法避免了复杂的递归或深度遍历,使得算法效率较高。
  • metaData 处理: 在构建 newItem 时,我们使用了对象解构 (const { level, ...restMetaData } = metaData;) 来将 level 属性从 metaData 中分离出来。这样,最终输出的 metaData 对象将不包含 level 属性,符合目标输出格式。
  • 数据顺序: 此算法假设输入数据是按照层级顺序大致排列的,即父节点通常在其子节点之前出现,或者至少在同一层级的兄弟节点之间,其父节点已经通过 itemMap 可访问。如果数据完全乱序,例如 level: 3 的项出现在其 level: 2 的父项之前,则 itemMap[parentLevel] 可能会找不到父项,导致子项无法正确归属。在实际应用中,如果数据顺序不可控,可能需要先对数据进行预排序。
  • 健壮性: 代码中增加了对 parentItem 是否存在的检查 (if (parentItem) )。如果由于数据问题导致父节点缺失,会发出警告,而不是直接报错。在生产环境中,可以根据业务需求选择更严格的错误处理机制。
  • 性能: 该算法通过单次遍历 (for...of) 完成数据转换,时间复杂度为 O(N),其中 N 是输入数组的长度。对于大多数应用场景,其性能表现良好。

5. 总结

通过 itemMap 这种巧妙的数据结构,我们能够高效且清晰地将扁平的层级数据转换为复杂的嵌套树形结构。这种模式在处理各种需要构建层次关系的数据时非常有用,如构建动态导航菜单、组织评论回复、或将文件路径转换为目录树等。理解并掌握这种转换技巧,是处理复杂数据结构的基础能力之一。

以上就是将扁平JSON数据转换为带层级的嵌套结构的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号