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

如何按指定属性分组合并数组对象以生成新数组项?

数组分组转换实现方案

问题描述

现有如下对象数组:

rows = [
    {
      id_temp: 1,
      description: 'template 1',
      color_id: 1,
      code: '#000000'
   },
    {
      id_temp: 1,
      description: 'template 1',
      color_id: 2,
      code: '#ffffff'
    },
   {
      id_temp: 2,
      description: 'template 2',
      color_id: 1,
      code: '#000000'
    },
   {
      id_temp: 2,
      description: 'template 2',
      color_id: 2,
      code: '#ffffff'
    },
]

需要将其转换为按id_temp分组的结构,新增color数组属性,包含对应color_id(作为id)和code:

[{
    "id_temp": 1,
    "description": "template 1",
    "color": [{
        "id": 1,
        "code": "#000000"
         },
        {
        "id": 2,
        "code": "#ffffff"
        }]
},
{
    "id_temp": 2,
    "description": "template 2",
    "color": [{
        "id": 1,
        "code": "#000000"
    },
    {
      "id": 2,
      "code": "#ffffff"
    }]
}]

尝试用forEach循环处理时出现值被覆盖的问题,错误代码如下:

let resultTemplates = [];
rows.forEach((row) => {
        if (resultTemplates[row.id_temp]) {
          resultTemplates['color'] = row.color_id;
          resultTemplates['color'] = row.code;
        } else {
          resultTemplates.id_temp = row.id_temp;
          resultTemplates.description = row.description;
          resultTemplates['color'].id = row.color_id;
          resultTemplates['color'].code = row.code;
        }
        });

错误原因分析

你的代码存在几个关键问题:

  • resultTemplates是数组,但你直接给它设置id_temp、description等属性,违背了数组的使用逻辑——数组应该存储对象元素,而非将数组本身当作对象赋值。
  • 判断resultTemplates[row.id_temp]时,数组索引从0开始,但id_temp是1、2,初始时resultTemplates[1]不存在,会进入else分支,此时resultTemplates['color']未初始化就直接赋值id和code,会触发报错。
  • 即使进入if分支,你直接给resultTemplates['color']赋值,会覆盖之前的数据,而非向数组中添加新元素。

正确实现方法

方法一:forEach+对象映射(性能更优)

通过临时对象按id_temp分组存储数据,最后将对象值转为目标数组:

const tempMap = {};
rows.forEach(row => {
    // 检查当前id_temp是否已在映射中
    if (!tempMap[row.id_temp]) {
        // 初始化分组对象
        tempMap[row.id_temp] = {
            id_temp: row.id_temp,
            description: row.description,
            color: []
        };
    }
    // 往color数组中添加当前颜色项
    tempMap[row.id_temp].color.push({
        id: row.color_id,
        code: row.code
    });
});

// 把映射对象的值转为目标数组
const resultTemplates = Object.values(tempMap);
console.log(resultTemplates);

方法二:reduce(写法更简洁)

利用Array.reduce一步完成分组和转换:

const resultTemplates = rows.reduce((acc, row) => {
    // 查找当前id_temp对应的分组对象
    const existing = acc.find(item => item.id_temp === row.id_temp);
    if (existing) {
        // 已存在则添加颜色项
        existing.color.push({ id: row.color_id, code: row.code });
    } else {
        // 不存在则新增分组对象
        acc.push({
            id_temp: row.id_temp,
            description: row.description,
            color: [{ id: row.color_id, code: row.code }]
        });
    }
    return acc;
}, []);

console.log(resultTemplates);

两种方法都能得到目标结构,其中方法一为O(n)时间复杂度,数据量较大时推荐使用;方法二写法更简洁,适合数据量较小的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 17:55:25