Add values of matching keys in array of objects

I have an array with a number of objects with matching keys:

[{a: 2, b: 5, c: 6}, {a:3, b: 4, d:1},{a: 1, d: 2}]

I want to loop through the array and if the keys match I want to add the results of each and return one object with the sum of each key.

i.e.

{a: 6, b: 9, c: 6, d: 3}

The code I currently have is

function combine() {
   var answer = [];
  for(var i in arguments){
    answer.push(arguments[i])
  }

 answer.reduce(function(o) {
    for (var p in o)
        answer[p] = (p in answer ? answer[p] : 0) + o[p];
        return answer;
    }, {});
}

I can find the answer here if I was to use the underscore library, however I wish to do it without using a library. I think I am having difficulty understanding how the reduce method works - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

Any help as to how to solve this would be greatly appreciated. Also, I feel it is an answer that should be somewhere on SO without having to use a library.

Thanks in advance.

Answers:

Answer

Loop through each object and add it.

    var a = [{a: 2, b: 5, c: 6}, {a:3, b: 4, d:1},{a: 1, d: 2}];
    var ans = {};

    for(var i = 0; i < a.length; ++i){
      for(var obj in a[i]){
       ans[obj] = ans[obj] ? ans[obj] + a[i][obj] : a[i][obj];
      }
    }
document.write(JSON.stringify(ans));


ans[obj] = ans[obj] ? ans[obj] + a[i][obj] : a[i][obj];

This line is the same as    
// check if the object already exists(or not falsy) in answer, if Yes add that value to the new value
if(ans[obj])
{
  ans[obj] = ans[obj] + a[i][obj];
}
// else create a new object in the answer and set it to the value from the array
else
{
  ans[obj] = a[i][obj];
}
Answer

Using Array.reduce() and Array.map()

var tab = [{a: 2, b: 5, c: 6}, {a:3, b: 4, d:1},{a: 1, d: 2}];

function sum(tab) {
  return tab.reduce((a, b) => {
    Object.keys(b).map(c => a[c] = (a[c] || 0) + b[c]);
    return a;
  });
}

console.log(sum(tab));
Answer

Your callback function in reduce() needs two arguments:

  1. The result returned for the previous value (or the initial value if the first one)
  2. The current value in the loop

You should also pass an empty object as a second parameter to reduce. This is the one you will fill in.

var input = [
  {a: 2, b: 5, c: 6},
  {a: 3, b: 4, d: 1},
  {a: 1, d: 2}
];

var answer = input.reduce(function(prev, curr) {
    for (var p in curr) {
        prev[p] = (prev[p] || 0) + curr[p];
    }

    return prev; // this will be passed as prev in the next iteration or returned as the result.
}, {}); // The {} is the initial value passed as prev

console.log(answer);

Answer

try this

resobj = {};
[{a: 2,b: 5,c: 6}, {a: 3,b: 4,d: 1}, {a: 1,d: 2}].forEach(function(v) {

  var keys = Object.keys(v);
  for (i = 0; i < keys.length; i++) {
    if (typeof resobj[keys[i]] == 'undefined') {
      resobj[keys[i]] = Number(v[keys[i]]);
    } else {
      resobj[keys[i]] += v[keys[i]];
    }
  }

})

document.write(JSON.stringify(resobj))

Answer

Yet another solution with reduce:

var result = [{a: 2, b: 5, c: 6}, {a:3, b: 4, d:1},{a: 1, d: 2}].reduce(function(prev, current) {
    Object.keys(current).forEach(function(key) {
        prev[key] = (prev[key] || 0) + current[key]; 
    });
    return prev;
}, {});

document.write('<pre>' + JSON.stringify(result, 0, 2) + '</pre>');

Answer

Just useArray#forEach() and an object for the result.

var data = [{ a: 2, b: 5, c: 6 }, { a: 3, b: 4, d: 1 }, { a: 1, d: 2 }],
    obj = {};

data.forEach(function (o) {
    Object.keys(o).forEach(function (k) {
        obj[k] = (obj[k] || 0) + o[k];
    });
})
document.write('<pre>' + JSON.stringify(obj, 0, 4) + '</pre>');

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.