Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sum similar keys in an array of objects

I have an array of objects like the following:

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

I need to add up all the values for objects with the same name. (Probably also other mathematical operations like calculate average.) For the example above the result would be:

[     {         'name': 'P1',         'value': 300     },     {         'name': 'P2',         'value': 200     },     {         'name': 'P3',         'value': 450     } ] 
like image 903
Sameer Joshi Avatar asked Jun 27 '14 05:06

Sameer Joshi


People also ask

How do you sum values in array of objects?

To sum a property in an array of objects:Initialize a sum variable, using the let keyword and set it to 0 . Call the forEach() method to iterate over the array. On each iteration, increment the sum variable with the value of the object.

Does object keys work on arrays?

The Object. keys() method returns an array of a given object's own enumerable property names, iterated in the same order that a normal loop would.


2 Answers

First iterate through the array and push the 'name' into another object's property. If the property exists add the 'value' to the value of the property otherwise initialize the property to the 'value'. Once you build this object, iterate through the properties and push them to another array.

Here is some code:

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);

Hope this helps.

like image 62
link Avatar answered Sep 21 '22 21:09

link


An ES6 approach to group by name:

You can convert your array of objects to a Map by using .reduce(). The Map has key-value pairs, where each key is the name, and each value is the accumulated sum of values for that particular name key. You can then easily convert the Map back into an array using Array.from(), where you can provide a mapping function that will take the keys/values of the Map and convert them into objects:

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);

Grouping by more than just name:

Here's an approach that should work if you have other overlapping properties other than just name (the keys/values need to be the same in both objects for them to "group"). It involves iterating through your array and reducing it to Map which holds key-value pairs. Each key of the new Map is a string of all the property values you want to group by, and so, if your object key already exists then you know it is a duplicate, which means you can add the object's current value to the stored object. Finally, you can use Array.from() to transform your Map of key-value pairs, to an array of just values:

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);
like image 43
Nick Parsons Avatar answered Sep 22 '22 21:09

Nick Parsons