如何从对象列表生成按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
相关产品推荐
相关产品推荐

