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

递归转换嵌套JSON为扁平结构并添加Id、typography、active字段

嵌套JSON转扁平JSON并添加标识字段(适配ReactDND)

问题描述

需要为嵌套JSON中的每个对象添加唯一ID、typography层级标识和active布尔字段,再转换为扁平JSON格式,用于ReactDND库。

原始嵌套JSON

[{
    "menuHead": [
      {
        "name": "MenuHead 01",
        "description": "sample Head 01",
        "icon": "sample01.png",
        "products": []
      },
      {
        "name": "MenuHead 02",
        "description": "sample Head 01",
        "icon": "sample01.png",
        "products01": [
          {
            "name": "product 01",
            "description": "sample product ONE",
            "icon": "product01.png",
            "section": [
              {
                "name": "section01",
                "description": "ActiveLayer",
                "icon": "img.png",
                "min": 100,
                "max": 1000
              },
              {
                "name": "section02",
                "description": "ActiveLayer",
                "icon": "img.png",
                "min": 500,
                "max": 1000
              },
              {
                "name": "section03",
                "description": "ActiveLayer",
                "icon": "img.png",
                "min": 100,
                "max": 600
              }
            ]
          },
          {
            "name": "product 02",
            "description": "sample product ONE",
            "icon": "product01.png",
            "section": [
              {
                "name": "section001",
                "description": "ActiveLayer",
                "icon": "img.png",
                "min": 100,
                "max": 1000
              },
              {
                "name": "section002",
                "description": "ActiveLayer",
                "icon": "img.png",
                "min": 500,
                "max": 1000
              },
              {
                "name": "section003",
                "description": "ActiveLayer",
                "icon": "img.png",
                "min": 100,
                "max": 600
              }
            ]
          }
        ]
      }
    ]
  }]

需求规则

  • 为每个对象添加唯一Id、typography层级字段和active布尔字段;
  • section层级对象的typography统一为2,active为false;
  • menuHead层级对象的typography为0,active为true;
  • products层级对象的typography为1,active为true;
  • 需采用递归方式实现,避免硬编码键名(如menuHead、products、section等),因为后续键名可能变更。

期望输出的扁平JSON

[
   {
     "name":"MenuHead 01",
     "description":"sample Head 01",
     "icon":"sample01.png",
      "id":1,
      "typography":0,
      "active":true
   },
   {
      "name":"MenuHead 02",
      "description":"sample Head 01",
      "icon":"sample01.png",
      "id":2,
      "typography":0,
      "active":true
   },
   {
      "name":"product 01",
      "description":"sample product ONE",
      "icon":"product01.png",
      "id":3,
      "typography":1,
      "active":true
   },
   {
       "name":"section01",
       "description":"ActiveLayer",
       "icon":"img.png",
       "min":100,
       "max":1000,
       "id":4,
       "typography":2,
       "active":false
   },
   {
      "name":"section02",
       "description":"ActiveLayer",
       "icon":"img.png",
       "min":500,
       "max":1000,
       "id":5,
       "typography":2,
       "active":false
   },
   {
      "name":"section03",
      "description":"ActiveLayer",
      "icon":"img.png",
       "min":100,
       "max":600,
        "id":6,
       "typography":2,
       "active":false
   },
   {
      "name":"product 02",
      "description":"sample product ONE",
      "icon":"product01.png",
      "id":7,
      "typography":1,
      "active":true
   },
   {
       "name":"section001",
       "description":"ActiveLayer",
       "icon":"img.png",
       "min":100,
       "max":1000,
       "id":8,
       "typography":2,
       "active":false
   },
   {
      "name":"section002",
       "description":"ActiveLayer",
       "icon":"img.png",
       "min":500,
       "max":1000,
       "id":9,
       "typography":2,
       "active":false
   },
   {
      "name":"section003",
      "description":"ActiveLayer",
      "icon":"img.png",
       "min":100,
       "max":600,
        "id":10,
       "typography":2,
       "active":false
   }
]

错误代码(运行出错)

const tree = [
   {
      "menuHead":[
         {
            "name":"MenuHead 01",
            "description":"sample Head 01",
            "icon":"sample01.png",
            "products":[
               {
                  "name":"product 01",
                  "description":"sample product ONE",
                  "icon":"product01.png",
                  "sections":[
                     {
                        "name":"section01",
                        "description":"ActiveLayer",
                        "icon":"img.png",
                        "min":100,
                        "max":1000
                     },
                     {
                        "name":"section02",
                        "description":"ActiveLayer",
                        "icon":"img.png",
                        "min":500,
                        "max":1000
                     },
                     {
                        "name":"section03",
                        "description":"ActiveLayer",
                        "icon":"img.png",
                        "min":100,
                        "max":600
                     }
                  ]
               }
            ]
         }
      ]
   }
]


 function addUniqueID(arr: any[], i: number) {
    arr.forEach((obj) => {
      obj.typography = i;
      obj.id = i + 1;
      obj.active = true;
      if (obj.menuHead) {
        addUniqueID(obj.menuHead, i + 1);
      }
      else if (obj.sections) {
        addUniqueID(obj.sections, i + 1);
      }
      else if (obj.products) {
        addUniqueID(obj.products, i + 1);
      } else {
        obj.active = false;
      }
    });
  }

  addUniqueID(tree, 0);

  console.log(tree)

  const c = (item: any) => "name" in item ? [{
    name: item.name,
    id: item.id,
    typography: item.typography,
    active: item.active,
    description:item.description,
    icon: item.icon,
    min:item.min,
    max:item.max
  }] : []

  function flat(item: any) {

    if ("products" in item) {
      return c(item).concat(item.products.flatMap(flat))
    }

    if ("sections" in item) {
      return c(item).concat(item.sections.flatMap(flat))
    }

    return (
      c(item)
    )
  }

  console.log(JSON.stringify (tree.flatMap(flat)))

修正后的实现代码

// 原始嵌套JSON数据
const rawData = [
  {
    "menuHead": [
      {
        "name": "MenuHead 01",
        "description": "sample Head 01",
        "icon": "sample01.png",
        "products": []
      },
      {
        "name": "MenuHead 02",
        "description": "sample Head 01",
        "icon": "sample01.png",
        "products01": [
          {
            "name": "product 01",
            "description": "sample product ONE",
            "icon": "product01.png",
            "section": [
              {
                "name": "section01",
                "description": "ActiveLayer",
                "icon": "img.png",
                "min": 100,
                "max": 1000
              },
              {
                "name": "section02",
                "description": "ActiveLayer",
                "icon": "img.png",
                "min": 500,
                "max": 1000
              },
              {
                "name": "section03",
                "description": "ActiveLayer",
                "icon": "img.png",
                "min": 100,
                "max": 600
              }
            ]
          },
          {
            "name": "product 02",
            "description": "sample product ONE",
            "icon": "product01.png",
            "section": [
              {
                "name": "section001",
                "description": "ActiveLayer",
                "icon": "img.png",
                "min": 100,
                "max": 1000
              },
              {
                "name": "section002",
                "description": "ActiveLayer",
                "icon": "img.png",
                "min": 500,
                "max": 1000
              },
              {
                "name": "section003",
                "description": "ActiveLayer",
                "icon": "img.png",
                "min": 100,
                "max": 600
              }
            ]
          }
        ]
      }
    ]
  }
];

// 生成唯一ID的计数器
let idCounter = 1;

/**
 * 递归处理嵌套对象,添加标识字段并收集扁平数据
 * @param data 待处理数据(对象或数组)
 * @param currentLevel 当前层级(用于确定typography)
 * @returns 扁平后的数组
 */
function processAndFlatten(data: any, currentLevel: number): any[] {
  const result: any[] = [];

  // 处理数组:遍历每个元素递归处理
  if (Array.isArray(data)) {
    data.forEach(item => {
      result.push(...processAndFlatten(item, currentLevel));
    });
    return result;
  }

  // 处理非数组对象:先判断是否是业务对象(有name字段)
  if (data.name) {
    // 根据层级设置typography和active
    let typography = currentLevel;
    let active = true;
    // 所有深度≥2的层级(section)强制typography=2,active=false
    if (currentLevel >= 2) {
      typography = 2;
      active = false;
    }

    // 复制原对象的所有字段,添加标识字段
    const processedItem = {
      ...data,
      id: idCounter++,
      typography,
      active
    };
    result.push(processedItem);
  }

  // 递归处理当前对象的所有数组类型属性(不硬编码键名)
  Object.keys(data).forEach(key => {
    const value = data[key];
    if (Array.isArray(value)) {
      // 数组属性的层级+1
      result.push(...processAndFlatten(value, currentLevel + 1));
    }
  });

  return result;
}

// 执行处理:从层级0开始,传入menuHead数组
const flattenedData = processAndFlatten(rawData[0].menuHead, 0);

console.log(JSON.stringify(flattenedData, null, 2));

关键修改说明

  • 移除硬编码键名:通过遍历对象所有键,自动识别数组类型属性进行递归处理,适配任意键名变更
  • 唯一ID生成:用全局计数器保证每个对象ID唯一,解决原代码中ID重复问题
  • 层级规则适配:
    • 根层级(menuHead)typography=0,active=true
    • 中间层级(products类)typography=1,active=true
    • 所有深度≥2的层级(section类)强制typography=2,active=false
  • 合并逻辑:将添加标识字段与扁平化合并为一个递归函数,减少遍历冗余
  • 兼容性:支持任意数组属性名(如products01),无需修改代码即可适配

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 06:51:18