这个对象数组怎么合并呢?

let list = [
    {name:'选项1',value:1},
    {name:'选项2',value:2},
    {name:'其他',value:3},
    {name:'其他',value:4},
    {name:'其他',value:5}
]

怎么把 name 等于选项 3 的合并成一条呢,然后把 value 加起来,比如合并成

[{name:'选项1',value:1},{name:'选项2',value:2},{name:'其他',value:12}]
阅读 1.1k
avatarAI BotBETA

您可以使用 JavaScript 的 reduce 方法来解决这个问题。reduce 方法会遍历数组中的每个元素,并将它们合并成一个新的对象。

这是如何使用 reduce 方法合并对象的示例代码:

let list = [{name:'选项1',value:1},{name:'选项2',value:2},{name:'其他',value:3},{name:'其他',value:4},{name:'其他',value:5}];

let merged = list.reduce((acc, curr) => {
  if (acc[curr.name]) {
    acc[curr.name].value += curr.value;
  } else {
    acc[curr.name] = curr;
  }
  return acc;
}, {});

list = Object.values(merged);

在这个示例中,我们首先创建一个空对象 acc 作为累加器。然后,我们遍历列表中的每个元素 curr。如果累加器中已经有一个与当前元素的 name 相同的键,我们就将当前元素的 value 加到累加器中对应元素的 value 上。如果累加器中没有这个键,我们就将当前元素添加到累加器中。最后,我们将累加器转换为一个数组,赋值给 list

4 个回答
let res = list.reduce((arr, item) => {
    let target = arr.find(citem => citem.name == item.name)

    if(target){
        target.value += item.value
    }else{
        arr.push({...item})
    }

    return arr
}, [])

修订:忘了结果需要的是一个数组。直接分组的结束常常是一个对象,但只需要取对象属性的值集就是数组结果了。所以下面的代码都加了个 Object.values() 来取结果。

@hfhan 的方法是直接把结果保存在数组中,通过 find 来查找,更直接一些。但是如果目标数组比较大的时候,这个查找比较耗时。用对象(映射表)是空间换时间的算法。

用 reduce 肯定是可以解决的

const groups = list
    .reduce((r, { name, value }) => {
        (r[name] ??= { name, value: 0 }).value += value;
        return r;
    }, {});

const result = Object.values(groups);

当然最适合初学者的方法是用循环

const result = {};

// 偷了个懒,循环变量用了解构语法
for (const { name, value } of list) {
    // (result[name] ??= { name, value: 0 }).value += value;
    // 下面的 if 语句块和上面这句是一样的效果
    if (name in result) {
        result[name].value += value;
    } else {
        result[name] = { name, value };
    }
}

const resultList = Object.values(result);
修订:加了个 resultList 取数组结果

如果用分步解决的思路,就是先分组,再映射,代码可以用 Lodash 来写(上面的 reduce 和 循环都是把这两步合并处理的)。

snipaste_2023-10-28_11-20-45.png

补两个参考:

示例代码:

[list[0], list[1], { name: '其他', value: list.slice(2).map(item => item.value).reduce((currrent, next) => currrent + next) }]

Input:

let list = [
    {name:'选项1',value:1},
    {name:'选项2',value:2},
    {name:'其他',value:3},
    {name:'其他',value:4},
    {name:'其他',value:5}
]

Output:

[
  { "name": "选项1", "value": 1 },
  { "name": "选项2", "value": 2 },
  { "name": "其他", "value": 12 }
]
新手上路,请多包涵

第一钟写法,先将同名的对象分组,再对每一组叠加,最后map处理成对应的结果

Object.entries( // 对象转数组
  Object.groupBy(list, ({name}) => name) // 同名的分组
).map(([name, group]) => ({ // 数组格式转换
  name,
  value: group.reduce((prev, {value}) => prev + value, 0) // 计算每组的值
}))

第二种写法先遍历一次转成对象,key是名字value是叠加值,最后将对象转成数组

Object.entries( // 对象转数组
  list.reduce((obj, {name, value}) => { // 遍历成对象,根据name进行叠加
    obj[name] = obj[name] ? obj[name] + value : value
    return obj
  }, {}) 
).map(([name, value]) => {name,value}) // 数组格式转换
推荐问题
宣传栏