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

将扁平化JSON数据转换为多级嵌套结构:JavaScript实现指南

聖光之護
发布: 2025-10-09 10:07:01
原创
1011人浏览过

将扁平化json数据转换为多级嵌套结构:javascript实现指南

本教程详细介绍了如何将包含层级信息的扁平化JSON数组转换为具有多级嵌套(subNav)结构的JSON对象。通过迭代处理数据并利用一个映射表追踪每个层级的最新节点,我们可以高效地构建出复杂的树形结构,从而实现数据的清晰组织和展示。

1. 理解问题:扁平化数据与目标结构

前端开发或数据处理中,我们经常会遇到需要将扁平化数组转换为具有层级关系的数据结构。假设我们有一个JSON数组,其中每个对象都包含一个metaData.level属性,表示其在层级结构中的深度:

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结构,其中子项通过subNav属性连接,如下所示:

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

直接通过数组索引判断父子关系(如root[index - 1])在多级嵌套中是不可行的,因为它无法准确追踪任意深度的父节点。我们需要一种更灵活的机制来识别并连接父子节点。

2. 核心思路:父节点追踪与层级映射

解决这个问题的关键在于,在遍历扁平化数组时,我们需要能够快速找到当前项的直接父节点。由于层级关系由metaData.level定义,我们可以维护一个映射表来存储每个层级的“最新”父节点。

立即学习Java免费学习笔记(深入)”;

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

具体步骤如下:

  1. 初始化结果数组:用于存放所有顶层(level: 1)的节点。
  2. 初始化层级映射表 (itemMap):这是一个对象,键是层级(例如1, 2, 3),值是该层级的最新节点对象。当处理一个level为N的项时,itemMap[N-1]将指向其父节点。
  3. 遍历扁平化数组:对每个元素执行以下操作:
    • 创建新节点:复制当前项的title和metaData到新节点,以便后续添加subNav。
    • 判断层级
      • 如果metaData.level为1,则该项是顶层节点,直接添加到结果数组中。
      • 如果metaData.level大于1,则计算其父级parentLevel(即currentLevel - 1)。
      • 从itemMap中获取parentLevel对应的父节点。
      • 如果父节点尚未有subNav属性,则初始化一个空数组。
      • 将当前新节点添加到父节点的subNav数组中。
    • 更新层级映射表:将当前新节点存储到itemMap[metaData.level]中。这样做是为了确保后续更深层级的子节点能够找到正确的直接父节点。

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数组转换为基于level属性的多级嵌套结构。
 * @param {Array<Object>} data 包含level属性的扁平化数据数组。
 * @returns {Array<Object>} 转换后的嵌套结构数组。
 */
function buildNestedStructure(data) {
  const topLevelItems = []; // 存储所有顶层(level 1)的节点
  const itemMap = {};       // 映射表,键为层级,值为该层级的最新节点

  for (const item of data) {
    const { title, metaData } = item;
    // 创建一个新对象,包含title和完整的metaData,避免直接修改原始数据
    const newItem = { title, metaData }; 

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

      if (!parentItem) {
        // 理论上不应该发生,除非数据顺序不正确(如level 2出现在level 1之前)
        console.warn(`Warning: Parent for level ${metaData.level} not found. Item:`, item);
        continue; 
      }

      // 如果父节点还没有 subNav 数组,则初始化
      if (!parentItem.subNav) {
        parentItem.subNav = [];
      }
      // 将当前节点添加到父节点的 subNav 中
      parentItem.subNav.push(newItem);
    }

    // 更新 itemMap,将当前节点设置为其所在层级的最新节点
    // 这样,后续同一层级或更深层级的节点可以找到正确的父节点
    itemMap[metaData.level] = newItem;
  }

  return topLevelItems;
}

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

4. 代码解析

  1. topLevelItems = []: 这个数组将保存最终输出的根节点。所有level: 1的项都会直接添加到这里。
  2. itemMap = {}: 这是算法的核心。它是一个哈希表(JavaScript对象),用于存储每个层级(level)的最后一个处理过的节点。
    • 当处理一个level为N的节点时,如果它是level: 1,它会被添加到topLevelItems。
    • 如果它是level: N > 1,它的父节点应该是level: N-1的某个节点。itemMap[N-1]会保存我们最近处理过的level: N-1的节点,这正是我们需要的父节点。
    • 处理完当前节点后,无论其level是多少,我们都会用它来更新itemMap[metaData.level]。这意味着,如果后续出现与当前节点同级或更深级的节点,它们将能够正确地找到父节点。
  3. for (const item of data): 遍历输入的扁平化数组。
  4. const newItem = { title, metaData };: 创建一个新对象。这里直接复制了原始的title和metaData,确保desc和displayOnOverview等额外属性也得以保留。
  5. if (metaData.level === 1): 如果当前项是顶层节点,直接将其添加到topLevelItems。
  6. else { ... }: 如果是子节点:
    • parentLevel = metaData.level - 1;: 确定父节点的层级。
    • parentItem = itemMap[parentLevel];: 从itemMap中获取对应的父节点。
    • if (!parentItem.subNav) { parentItem.subNav = []; }: 如果父节点还没有subNav数组,就创建一个。
    • parentItem.subNav.push(newItem);: 将当前节点添加到父节点的subNav中。
  7. itemMap[metaData.level] = newItem;: 关键步骤。将当前处理的newItem存入itemMap,以其metaData.level作为键。这样,如果后续有同级或更深层级的节点,它就能成为它们的父节点。

5. 注意事项与扩展

  • 数据顺序:此方法假设输入数据是按层级顺序组织的,即一个父节点总是出现在其所有子节点之前。如果数据顺序混乱(例如,level: 2的节点出现在其level: 1的父节点之前),itemMap[parentLevel]可能无法找到正确的父节点,导致结构错误或警告。
  • 错误处理:在parentItem = itemMap[parentLevel];之后,可以添加更健壮的错误检查,例如if (!parentItem) { throw new Error("Parent item not found for level " + metaData.level); },以处理数据结构不一致的情况。
  • 性能:该算法对输入数组进行了一次遍历,时间复杂度为O(N),其中N是数组的长度,效率较高。
  • 灵活性:如果嵌套属性名(如subNav)或层级属性名(如metaData.level)可能变化,可以将它们作为参数传递给函数,提高代码的通用性。
  • 深拷贝:示例中newItem = { title, metaData }是浅拷贝了metaData对象。如果需要确保metaData在后续操作中不会影响原始item,可以使用JSON.parse(JSON.stringify(item))或structuredClone(item)进行深拷贝。

6. 总结

通过维护一个层级映射表,我们可以有效地将扁平化的JSON数组转换为任意深度的嵌套结构。这种方法既高效又灵活,是处理此类数据转换问题的常用模式。理解itemMap在追踪父节点和更新当前层级最新节点方面的作用,是掌握这一技巧的关键。

以上就是将扁平化JSON数据转换为多级嵌套结构:JavaScript实现指南的详细内容,更多请关注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号