Sum javascript object propertyA values ​​with the same property of object B in an array of objects

How to take a javascript array of objects such as:

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 combine duplicate keys by summing the values. 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 tried iterating and adding to a new array, but that 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 
+9
source share
6 answers

You must assign each object not found as a result with its .key property.

If it is found, you need to add it .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 reused the item variable to refer to the .key value, so you lost the reference to the object.

+9
source

Instead of using a for loop and sending values, you can directly use the map and reduce :

 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); 
+5
source

You can use the hash table to group by 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 the key / value pairs in Map and format the final array with Array.from and a callback for the objects.

 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; } 
+4
source
 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/

+3
source

Here is an alternative for you, but similar to that of Explosion Pills , reusing the original array, rather than creating a new or different object. The variety may not be needed and will slow down a little, but it can be removed.

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

And jsperf that compares this (with and without sorting) with the accepted answer. You can improve your performance test by expanding your data set.

0
source

you can also try using the javascript linq framework, which is exactly the same as the sql statement, which gets the desired result with less code written and is efficient and found in 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 to compare with a loop. Hope this helps.

0
source

Source: https://habr.com/ru/post/955441/


All Articles