将对象数组中具有相同对象 propertyB 的 javascript 对象 propertyA 值求和

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19233283/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 14:50:11  来源:igfitidea点击:

Sum javascript object propertyA values with same object propertyB in array of objects

javascriptarraysjsonobjectreduce

提问by AlecPerkey

How would one take a javascript array of objects such as:

如何使用 javascript 对象数组,例如:

my objArr = [
{key:Mon Sep 23 2013 00:00:00 GMT-0400, val:42},
{key:Mon Sep 24 2013 00:00:00 GMT-0400, val:78},
{key:Mon Sep 25 2013 00:00:00 GMT-0400, val:23},
{key:Mon Sep 23 2013 00:00:00 GMT-0400, val:54}]

and merge duplicate keys by summing the values. In order to get something like this:

并通过对值求和来合并重复的键。为了得到这样的东西:

my reducedObjArr = [
{key:Mon Sep 23 2013 00:00:00 GMT-0400, val:96},
{key:Mon Sep 24 2013 00:00:00 GMT-0400, val:78},
{key:Mon Sep 25 2013 00:00:00 GMT-0400, val:23}]

I have tried iterating and adding to a new array, but this didn't work:

我试过迭代并添加到一个新数组中,但这不起作用:

var reducedObjArr = [];
var item = null, key = null;
for(var i=0; i<objArr.length; i++) {
   item=objArr[i];
   key = Object.keys(item)[0];
   item=item[key];

   if(!result[key]){
       result[key] = item;
   }else{
       result[key] += item;}
   }a

回答by user2736012

You should be assigning each object not found to the result with its .keyproperty.

您应该将未找到的每个对象分配给具有其.key属性的结果。

If it is found, then you need to add its .val.

如果找到了,那么你需要添加它的.val.

var temp = {};
var obj = null;
for(var i=0; i < objArr.length; i++) {
   obj=objArr[i];

   if(!temp[obj.key]) {
       temp[obj.key] = obj;
   } else {
       temp[obj.key].val += obj.val;
   }
}
var result = [];
for (var prop in temp)
    result.push(temp[prop]);


Also, part of the problem was that you were reusing the itemvariable to reference the value of .key, so you lost reference to the object.

此外,部分问题是您正在重用item变量来引用 的值.key,因此您丢失了对对象的引用。

回答by Hamms

Rather than using a for loop and pushing values, you can directly use mapand reduce:

您可以直接使用mapreduce,而不是使用 for 循环和推送值:

let objArr = [
  {key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 42},
  {key: 'Mon Sep 24 2013 00:00:00 GMT-0400', val: 78},
  {key: 'Mon Sep 25 2013 00:00:00 GMT-0400', val: 23},
  {key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 54}
];

// first, convert data into a Map with reduce
let counts = objArr.reduce((prev, curr) => {
  let count = prev.get(curr.key) || 0;
  prev.set(curr.key, curr.val + count);
  return prev;
}, new Map());

// then, map your counts object back to an array
let reducedObjArr = [...counts].map(([key, value]) => {
  return {key, value}
})

console.log(reducedObjArr);

回答by Nina Scholz

You could use a hash table for the grouping by key.

您可以使用哈希表进行分组key

var array = [{ key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 42 }, { key: 'Mon Sep 24 2013 00:00:00 GMT-0400', val: 78 }, { key: 'Mon Sep 25 2013 00:00:00 GMT-0400', val: 23 }, { key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 54}],
    grouped = [];

array.forEach(function (o) {
    if (!this[o.key]) {
        this[o.key] = { key: o.key, val: 0 };
        grouped.push(this[o.key]);
    }
    this[o.key].val += o.val;
}, Object.create(null));

console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Another approach is to collect all key/value pairs in a Mapand format the final array with Array.fromand a callback for the objects.

另一种方法是在 a 中收集所有键/值对,Map并使用Array.from对象的回调格式化最终数组。

var array = [{ key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 42 }, { key: 'Mon Sep 24 2013 00:00:00 GMT-0400', val: 78 }, { key: 'Mon Sep 25 2013 00:00:00 GMT-0400', val: 23 }, { key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 54 }],
    grouped = Array.from(
        array.reduce((m, { key, val }) => m.set(key, (m.get(key) || 0) + val), new Map),
        ([key, val]) => ({ key, val })
    );

console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }

回答by Explosion Pills

var targetObj = {};
for (var i = 0; i < objArr.length; i++) {
    if (!targetObj.hasOwnProperty(objArr[i].key)) {
        targetObj[objArr[i].key] = 0;
    }
    targetObj[objArr[i].key] += objArr[i].val;
}

http://jsfiddle.net/HUMxp/

http://jsfiddle.net/HUMxp/

回答by besar

Try this, it should help

试试这个,它应该有帮助

var arr1 = [
    { name: 'besart', value: 12 },
    { name: 'astrit', value: 10 },
    { name: 'astrit', value: 10 },
    { name: 'besar', value: 18 },
    { name: 'besar', value: 3 },
    { name: 'astrit', value: 3 },
    { name: 'besart', value: 3 },
    { name: 'besart', value: 10 },
    { name: 'besar', value: 0 },
];

var arr2 = [];
var emri = "";
var value = 0;
for(var i = 0;i<arr1.length;i++){
    emri=arr1[0].name;
    value+=arr1[0].value;
    for(var j=1;j<arr1.length;j++){
        if(emri==arr1[j].name){
            value+=arr1[j].value;
            arr1.splice(j,1);
            j--;
        }
    }
    arr1.splice(0,1);
    arr2[i] = {name:emri,value:value};
    value=0;
}
console.log(arr2);

Below is another solution that uses only one loop (while loop):

下面是另一种仅使用一个循环(while 循环)的解决方案:

 var arr2 = [];
    var emri = "";
    var value = 0;
    var i=1;
    var j=0;

while(arr1.length != 0){
        emri = arr1[0].name;
        if(emri == arr1[i].name){
            value+=arr1[i].value;
            arr1.splice(i,1);
            i--;
        }
        i++;
        if(i==arr1.length){
            value+=arr1[0].value;
            i=1;
            arr2[j]={name:emri,value:value};
            j++;
            value=0;
            arr1.splice(0,1);
        }
    }

回答by mplungjan

Simpler reduce than posted elsewhere

比其他地方张贴的更简单的减少

const objArr = [
{key:"Mon Sep 23 2013 00:00:00 GMT-0400", val:42},
{key:"Mon Sep 24 2013 00:00:00 GMT-0400", val:78},
{key:"Mon Sep 25 2013 00:00:00 GMT-0400", val:23},
{key:"Mon Sep 23 2013 00:00:00 GMT-0400", val:54}];

const output = objArr.reduce((accumulator, cur) => {
  let date = cur.key;
  let found = accumulator.find(elem => elem.key === date)
  if (found) found.val += cur.val;
  else accumulator.push(cur);
  return accumulator;
}, []);

console.log(output)

回答by Xotic750

Here is an alternative for you, but similar to that of Explosion Pills, reuses the original array rather than creating a new one or a different object. The sort may not be necessary and will slow things down a little, but it could be removed.

这是您的替代方案,但类似于Explosion Pills,重用原始数组而不是创建新的或不同的对象。排序可能不是必需的,并且会稍微减慢速度,但可以将其删除。

Javascript

Javascript

function reduceMyObjArr(arr) {
    var temp = {},
        index;

    for (index = arr.length - 1; index >= 0; index -= 1) {
        key = arr[index].key;
        if (temp.hasOwnProperty(key)) {
            arr[temp[key]].val += arr[index].val;
            arr.splice(index, 1);
        } else {
            temp[key] = index;
        }
    }

    arr.sort(function (a, b) {
        if (a.key === b.key) {
            return 0;
        }

        if (a.key < b.key) {
            return -1;
        }

        return 1;
    });

    return arr;
}

var myObjArr = [{
    key: "Mon Sep 23 2013 00: 00: 00 GMT - 0400",
    val: 42
}, {
    key: "Mon Sep 24 2013 00: 00: 00 GMT - 0400",
    val: 78
}, {
    key: "Mon Sep 25 2013 00: 00: 00 GMT - 0400",
    val: 23
}, {
    key: "Mon Sep 23 2013 00: 00: 00 GMT - 0400",
    val: 54
}];

reduceMyObjArr(myObjArr);

console.log(myObjArr);

jsFiddle

js小提琴

And a jsperfthat compares this (with and without the sort) against the accepted answer. You can improve the performance test by extending the data set.

一个jsperf将这个(有和没有排序)与接受的答案进行比较。您可以通过扩展数据集来改进性能测试。

回答by Astrit Spanca

Recently l needed a similar implementation and l used a similar solution offered by some guy that used reduce function. Few days later i wanted to implement something similar by myself and here is the result.

最近我需要一个类似的实现,我使用了一些使用 reduce 函数的人提供的类似解决方案。几天后,我想自己实现类似的东西,结果如下。

const users = [
        { id: 1, name: 'ernest', spent: 40 }, 
        { id: 2, name: 'ernest', spent: 40 },
        { id: 3, name: 'astrit', spent: 22 },
        { id: 4, name: 'astrit', spent: 2956 },
        { id: 5, name: 'astrit', spent: 22 }, 
        { id: 6, name: 'besart', spent: 40 }, 
        { id: 7, name: 'besart', spent: 100}, 
        { id: 8, name: 'besart', spent: 4000 }
    ];

        const sum = [];

        users.forEach(el => {
            if(sum.length === 0){
                delete el.id;
                sum.push(el);
            }    
            else
            {
                const get = () => {
                    for(let i = 0; i < sum.length; i++){
                        if(sum[i].name === el.name ){
                            return { stat: true, id: i };
                        }
                    }
                }

                let i = get();
                if(i){
                    sum[i.id].spent += el.spent;
                }
                else
                {
                    delete el.id;
                    sum.push(el);
                }
            }
        });

        console.log(sum);

Output:

输出:

[ { name: 'ernest', spent: 80 }, { name: 'astrit', spent: 3000 }, { name: 'besart', spent: 4140 } ]

回答by Sanjay Radadiya

you can also try using javascript linq framework which is exactly same as sql statement which is given desired output with less written code and effective and found at linq.js

您也可以尝试使用与 sql 语句完全相同的 javascript linq 框架,该框架以较少的编写代码和有效的方式提供所需的输出,并在 linq.js 中找到

var objArr = 
[
{key:'Mon Sep 23 2013 00:00:00 GMT-0400', val:42},
{key:'Mon Sep 24 2013 00:00:00 GMT-0400', val:78},
{key:'Mon Sep 25 2013 00:00:00 GMT-0400', val:23},
{key:'Mon Sep 23 2013 00:00:00 GMT-0400', val:54}
];


var aggregatedObject = Enumerable.From(objArr)
        .GroupBy("$.key", null,
                 function (key, g) {
                     return {
                       key: key,
                       contributions: g.Sum("$.val")
                     }
        })
        .ToArray();

console.log(aggregatedObject);
<script src="http://cdnjs.cloudflare.com/ajax/libs/linq.js/2.2.0.2/linq.min.js"></script>

which is pretty easy as compare to looping. i hope this may help.

与循环相比,这很容易。我希望这会有所帮助。