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

如何从对象列表生成按a值聚合的嵌套对象列表?

如何将重复a值的数组转换为按a分组、b为数组的嵌套对象列表

你想要把包含重复a值的数组,转换为每个a对应唯一条目、b为对应所有值的数组,这个需求很常见,咱们先分析你现有代码的问题,再给出更优的解法。

问题回顾

原始数据

const tempData = [ {a: 1557637200025, b: "aaaa"}, {a: 1557637200025, b: "bbbb"}, {a: 1557637200025, b: "cccc"}, {a: 1557637200025, b: "dddd"}, {a: 1557637200025, b: "eeee"}, {a: 1557637200025, b: "ffff"}, {a: 1557637200025, b: "gggg"}, {a: 1555563600017, b: "hhhh"}, {a: 1555563600017, b: "iiii"}, {a: 1555563600017, b: "jjjj"}, {a: 1555563600017, b: "kkkk"}, {a: 1555563600017, b: "llll"}, {a: 1555563600017, b: "mmmm"}, {a: 1555563600017, b: "nnnn"}, {a: 1555563600017, b: "oooo"}, {a: 1555563600017, b: "pppp"}, {a: 1555563600017, b: "qqqq"}, {a: 1555563600017, b: "rrrr"}, {a: 1555563600017, b: "ssss"}, {a: 1555563600017, b: "tttt"}, {a: 1555563600017, b: "uuuu"}, {a: 1557982800028, b: "vvvv"}, ];

期望输出

const newTempData = [ 
  { a: 1557637200025,b: [ "aaaa", "bbbb", "cccc", "dddd", "eeee", "ffff", "gggg" ]}, 
  { a: 1555563600017,b: [ "hhhh", "iiii", "jjjj", "kkkk", "llll", "mmmm", "nnnn", "oooo", "pppp", "qqqq", "rrrr", "ssss", "tttt", "uuuu" ]},
  { a: 1557982800028,b: [ "vvvv" ]}
];

现有代码的问题

你用嵌套for循环的思路是对的,但逻辑有误:每次遍历row1(数组的每个元素),都会重新遍历整个数组收集所有相同a的b值,然后把这个分组结果push到newTempData里。这就导致每个原始元素都会生成一个重复的分组条目,比如a=1557637200025有7个元素,结果里就会出现7次相同的分组,自然不符合预期。


高效解决方案

方法1:使用Array.reduce()(推荐,简洁高效)

reduce是处理数组分组场景的绝佳工具,它可以在一次遍历中完成分组逻辑:

const tempData = [ /* 你的原始数据 */ ];

const newTempData = Object.values(tempData.reduce((acc, item) => {
  // 如果当前a值还没在累加器中,初始化一个分组对象
  if (!acc[item.a]) {
    acc[item.a] = { a: item.a, b: [] };
  }
  // 将当前元素的b值添加到对应分组的b数组中
  acc[item.a].b.push(item.b);
  return acc;
}, {}));

console.log(newTempData);

逻辑说明:

  • 用一个对象acc作为累加器,键是a的值,值是我们要构建的分组对象
  • 遍历每个元素时,检查acc中是否存在当前a的分组:不存在则创建,存在则直接追加b值
  • 最后用Object.values()把累加器对象的所有值提取为数组,就是最终的无重复分组结果

方法2:普通循环+中间映射对象(逻辑更直观)

如果你对reduce不太熟悉,可以用这种更直白的方式,核心是用一个映射对象记录已创建的分组,避免重复:

const tempData = [ /* 你的原始数据 */ ];
const groupMap = {}; // 记录每个a对应的分组对象
const newTempData = [];

for (const item of tempData) {
  if (!groupMap[item.a]) {
    // 若当前a未分组,创建新分组并同时加入结果数组和映射对象
    const group = { a: item.a, b: [] };
    groupMap[item.a] = group;
    newTempData.push(group);
  }
  // 通过映射对象直接找到对应分组,追加b值
  groupMap[item.a].b.push(item.b);
}

console.log(newTempData);

逻辑说明:

  • groupMap的作用是缓存已创建的分组,键为a的值,值为分组对象的引用
  • 遍历元素时,若a不在映射中,就创建新分组并加入结果数组和映射;否则直接通过映射找到分组,添加b值
  • 这种方式同样是一次遍历,效率和reduce相当,逻辑更易理解

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:55:23