对对象数组中的相似键求和

IT技术 javascript arrays object
2021-01-13 04:36:07

我有一个对象数组,如下所示:

[
    {
        'name': 'P1',
        'value': 150
    },
    {
        'name': 'P1',
        'value': 150
    },
    {
        'name': 'P2',
        'value': 200
    },
    {
        'name': 'P3',
        'value': 450
    }
]

我需要将同名对象的所有值相加。(可能还有其他数学运算,例如计算平均值。)对于上面的示例,结果将是:

[
    {
        'name': 'P1',
        'value': 300
    },
    {
        'name': 'P2',
        'value': 200
    },
    {
        'name': 'P3',
        'value': 450
    }
]
6个回答

首先遍历数组并将“名称”推送到另一个对象的属性中。如果属性存在,则将“值”添加到属性的值,否则将属性初始化为“值”。构建此对象后,遍历属性并将它们推送到另一个数组。

这是一些代码:

var obj = [
    { 'name': 'P1', 'value': 150 },
    { 'name': 'P1', 'value': 150 },
    { 'name': 'P2', 'value': 200 },
    { 'name': 'P3', 'value': 450 }
];

var holder = {};

obj.forEach(function(d) {
  if (holder.hasOwnProperty(d.name)) {
    holder[d.name] = holder[d.name] + d.value;
  } else {
    holder[d.name] = d.value;
  }
});

var obj2 = [];

for (var prop in holder) {
  obj2.push({ name: prop, value: holder[prop] });
}

console.log(obj2);

希望这可以帮助。

嗨,我的对象如下所示如何处理?var obj = [ { 'name': 'P1', 'value': [150, 11] }, { 'name': 'P1', 'value': [150, 12] }, { 'name': ' P2', 'value': [200, 13] }, { 'name': 'P3', 'value': [450, 14] } ];
2021-03-23 04:36:07
这是一个很老的问题。从那时我就开始使用 Lodash ( lodash.com )。您可以轻松地使用sumsumByMath 函数来实现原始查询中的要求
2021-03-30 04:36:07

ES6 分组方式name

您可以将对象的数组转换为一个地图使用.reduce()Map 具有键值对,其中每个键是name,每个value是该特定name键值的累积总和然后,您可以使用 轻松地将 Map 转换回数组Array.from(),您可以在其中提供一个映射函数,该函数将获取 Map 的键/值并将它们转换为对象:

const arr = [ { 'name': 'P1', 'value': 150 }, { 'name': 'P1', 'value': 150 }, { 'name': 'P2', 'value': 200 }, { 'name': 'P3', 'value': 450 } ];

const res = Array.from(arr.reduce(
  (m, {name, value}) => m.set(name, (m.get(name) || 0) + value), new Map
), ([name, value]) => ({name, value}));
console.log(res);

分组不仅仅是name

如果您有其他重叠的属性而不只是name(两个对象中的键/值需要相同才能“分组”),那么这是一种应该有效的方法它涉及遍历您的数组并将其缩减为包含键值对的 Map。新 Map 的每个键都是您想要分组的所有属性值的字符串,因此,如果您的对象键已经存在,那么您知道它是重复的,这意味着您可以将对象的当前值添加到存储的对象中. 最后,您可以使用Array.from()将键值对映射转换为仅包含值的数组:

const arr = [{'name':'P1','value':150},{'name':'P1','value':150},{'name':'P2','value':200},{'name':'P3','value':450}];

const res = Array.from(arr.reduce((acc, {value, ...r}) => {
  const key = JSON.stringify(r);
  const current = acc.get(key) || {...r, value: 0};  
  return acc.set(key, {...current, value: current.value + value});
}, new Map).values());
console.log(res);

@SiddharthAgrawal 第一个例子是O(N),哪里Narr. 第二个例子是O(NK),其中K是属性的在阵列内的对象的(最大)数目。如果您采用排序方法,您可以获得的最佳复杂度(对于基于比较的排序)是O(NlogN),它大于O(N)解决方案
2021-03-16 04:36:07
请问,除了使用“object.entries”之外,有没有更好的方法来实现它?
2021-03-20 04:36:07
@BaiClassmateXiao 我也尝试了这个答案,这对满足我的要求非常有帮助。我已经定制了这个。我还需要为多个键执行此操作.. 只需传递另一个带有 value、value1 等参数的参数..
2021-03-27 04:36:07
@SiddharthAgrawal 计算平均值,您可以使用与上述相同的方法进行分组,但是。为每个值存储一个具有名称、值和计数的对象(您看到具有相同对象的次数name),然后使用 array.from 的第二个参数将这些对象转换回您想要的格式,在那里您可以使用count求平均值。我做了这个例子
2021-03-28 04:36:07
对不起,如果你遇到这种类型的数据,它不起作用 [{ id: 10, name: "abc", quantity: 2 }, { id: 10, name: "abc", quantity: 1 } ]
2021-03-31 04:36:07

您可以使用Array.reduce()在每次迭代期间累积结果。

var arr = [{'name':'P1','value':150},{'name':'P1','value':150},{'name':'P2','value':200},{'name':'P3','value':450}];

var result = arr.reduce(function(acc, val){
    var o = acc.filter(function(obj){
        return obj.name==val.name;
    }).pop() || {name:val.name, value:0};
    
    o.value += val.value;
    acc.push(o);
    return acc;
},[]);

console.log(result);

我猜还有一种解决方案是干净的

 

    var obj =  [
        { 'name': 'P1', 'value': 150 },
        { 'name': 'P1', 'value': 150 },
        { 'name': 'P2', 'value': 200 },
        { 'name': 'P3', 'value': 450 }
    ];

     var result = [];
Array.from(new Set(obj.map(x => x.name))).forEach(x => {

    result.push(obj.filter(y => y.name === x).reduce((output,item) => {
        let val = output[x] === undefined?0:output[x];
        output[x] =  (item.value +  val); 
       return output;
    },{}));

 })
      
            console.log(result);

如果您需要保持对象结构相同,

var obj =  [
    { 'name': 'P1', 'value': 150 },
    { 'name': 'P1', 'value': 150 },
    { 'name': 'P2', 'value': 200 },
    { 'name': 'P2', 'value': 1000 },
    { 'name': 'P3', 'value': 450 }
];

let output = [];
let result = {};
let uniqueName = Array.from(new Set(obj.map(x => x.name)));
uniqueName.forEach(n => {
   output.push(obj.filter(x => x.name === n).reduce((a, item) => {
      
       let val = a['name'] === undefined? item.value:a['value']+item.value;
        
        return {name:n,value:val};
    },{})
);
});

console.log(output);

出于某种原因,当我通过@Vignesh Raja 运行代码时,我获得了“总和”,但也获得了重复的项目。因此,我必须删除重复项,如下所述。

原始数组:

arr=[{name: "LINCE-01", y: 70}, 
 {name: "LINCE-01", y: 155},
 {name: "LINCE-01", y: 210},
 {name: "MIRAFLORES-03", y: 232},
 {name: "MIRAFLORES-03", y: 267}]

使用@VigneshRaja 的代码:

var result = arr.reduce(function(acc, val){
    var o = acc.filter(function(obj){
        return obj.name==val.name;
    }).pop() || {name:val.name, y:0};

    o.y += val.y;
    acc.push(o);
    return acc;
},[]);

console.log(result);

第一个结果:

result: [{name: "LINCE-01", y: 435},
 {name: "LINCE-01", y: 435},
 {name: "LINCE-01", y: 435},
 {name: "MIRAFLORES-03", y: 499},
 {name: "MIRAFLORES-03", y: 499}]

删除重复项:

var finalresult = result.filter(function(itm, i, a) {
                            return i == a.indexOf(itm);
                        });
console.log(finalresult);

最后,我得到了我想要的:

finalresult = [{name: "LINCE-01", y: 435},
 {name: "MIRAFLORES-03", y: 657}]

问候,