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

如何展开含数组的对象数组?递归实现遇阻求助

解决方案

要实现你需要的嵌套JSON展开逻辑,核心是先提取所有扁平化字段,再根据最长数组的长度生成对应数量的对象,后续对象仅填充当前索引的有效值,重复字段设为undefined,同时添加排序用的key字段。

关键思路

  • 扁平化字段提取:递归遍历原始JSON,把嵌套结构转换成父键.子键格式的扁平字段,同时记录每个数组字段的元素列表
  • 确定对象数量:以所有数组中长度最大的那个为基准,决定要生成多少个对象
  • 填充对象内容:第一个对象填充所有字段的第一个有效值;后续对象仅填充当前索引存在值的字段,其余重复字段设为undefined,并设置递增的key

修正后的代码

// 辅助函数:判断是否为对象
function isObject(item) {
  return item && typeof item === 'object' && !Array.isArray(item);
}

// 递归提取扁平化字段和对应的数据列表
function extractFlatFields(obj, parentKey = '', result = { fields: [], dataMap: {} }) {
  Object.entries(obj).forEach(([key, value]) => {
    const currentKey = parentKey ? `${parentKey}.${key}` : key;
    
    if (Array.isArray(value)) {
      // 处理数组:记录每个元素的扁平化数据
      result.dataMap[currentKey] = value.map(item => {
        const itemData = {};
        extractFlatFields(item, currentKey, { fields: [], dataMap: itemData });
        // 把嵌套的扁平字段展开到当前层级
        return Object.fromEntries(
          Object.entries(itemData).map(([k, v]) => [k.replace(`${currentKey}.`, ''), v])
        );
      });
      // 把数组元素的子字段加入总字段列表
      value.forEach(item => extractFlatFields(item, currentKey, result));
    } else if (isObject(value)) {
      extractFlatFields(value, currentKey, result);
    } else {
      if (!result.fields.includes(currentKey)) {
        result.fields.push(currentKey);
      }
      // 非数组非对象的字段,用数组包装(方便统一处理)
      result.dataMap[currentKey] = [value];
    }
  });
  return result;
}

// 生成最终的展开结果
function expandNestedJSON(data) {
  const input = Array.isArray(data) ? data[0] : data;
  const { fields, dataMap } = extractFlatFields(input);
  
  // 找到最长的数组长度,确定要生成的对象数量
  const maxLength = Math.max(...Object.values(dataMap).map(arr => arr.length));
  
  // 生成每个对象
  return Array.from({ length: maxLength }, (_, index) => {
    const obj = {};
    fields.forEach(field => {
      // 拆分字段,找到对应的数组和子字段
      const [rootKey, ...subKeys] = field.split('.');
      const arr = dataMap[rootKey];
      
      if (arr && arr[index]) {
        let value = arr[index];
        // 处理子字段(比如b.c对应arr[index].c)
        for (const subKey of subKeys) {
          value = value?.[subKey];
        }
        obj[field] = value !== undefined ? value : undefined;
      } else {
        // 只有第一个对象填充,后续设为undefined
        obj[field] = index === 0 ? dataMap[field]?.[0] : undefined;
      }
    });
    // 设置key字段
    obj.key = index + 1;
    return obj;
  });
}

// 测试输入
const input = [
  {
    a: '1',
    b: [
        { c: '3', d: '4' },
        { c: '5' },
        { c: '7', d: '8' }
    ],
    f: [ { d: '6' }, { d: '9' } ],
    e: [ { g: '9' } ]
  }
];

// 生成结果
const output = expandNestedJSON(input);
console.log(JSON.stringify(output, null, 2));

代码说明

  1. extractFlatFields函数:递归遍历原始JSON,把所有嵌套字段转换成扁平格式(如b.c),同时用dataMap记录每个字段对应的数据列表(数组类型的字段直接存元素列表,非数组字段存单元素数组)
  2. expandNestedJSON函数:
    • 先获取最长数组的长度,确定要生成的对象总数
    • 逐个生成对象:第一个对象填充所有字段的初始值;后续对象仅填充当前索引有对应值的字段,其余重复字段设为undefined
    • 给每个对象添加递增的key字段,用于排序

输出结果

运行代码后会得到你期望的输出:

[
  {
    "a": "1",
    "b.c": "3",
    "b.d": "4",
    "f.d": "6",
    "e.g": "9",
    "key": 1
  },
  {
    "a": undefined,
    "b.c": "5",
    "b.d": undefined,
    "f.d": "9",
    "e.g": undefined,
    "key": 2
  },
  {
    "a": undefined,
    "b.c": "7",
    "b.d": "8",
    "f.d": undefined,
    "e.g": undefined,
    "key": 3
  }
]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 17:24:27