Shan
Shan

Reputation: 3

How to get an object containing the sum of all items in an arrays of objects?

I have an array of objects where each index is one week where I bought groceries. Meaning that array[0] is the first week, array[1] is the second and the so on. What I need to do is do sum all the values of the same items using Underscore (not for loop, or while). Here is one example:

   console.log(weeklyGroceries([
                                  {
                                    apple: 1,
                                    banana: 4,
                                    fish: 2,
                                    melon: 3,
                                  },
                                  {
                                    apple: 3,
                                    banana: 2,
                                    fish: 5,
                                    melon: 1,
                                  }
                                ]));

It should print:

{
apple: 4,
banana: 6,
fish: 27,
melon: 4
}

Any ideas?

I have tried using reduce to get all the values, but I still have to sum the same values it wouldn't be in object form anymore.

var keys = array.reduce((value,obj) => [...value, ...Object.values(obj)],[]);

Upvotes: 0

Views: 187

Answers (4)

Julian
Julian

Reputation: 4366

Here is a fun exercise in functional programming. Assuming you already have a sum function for simple arrays of numbers, you can implement weeklyGroceries in just two expressions. No loops, anonymous functions or if/else required:

var add = (a, b) => a + b;
var sum = _.partial(_.reduce, _, add, 0);

function weeklyGroceries(groceriesByDay) {
    var keys = _.chain(groceriesByDay)
    .map(_.keys).flatten().uniq().value();
    return _.chain(keys).zip(keys).object()
    .mapObject(_.property)
    .mapObject(_.partial(_.map, groceriesByDay))
    .mapObject(_.compose(sum, _.compact))
    .value();
}

console.log(weeklyGroceries([{
    apple: 1,
    banana: 4,
    fish: 2,
    melon: 3,
}, {
    apple: 3,
    banana: 2,
    fish: 5,
    melon: 1,
}]));
<script src="https://cdn.jsdelivr.net/npm/[email protected]/underscore-umd-min.js"></script>

While the implementation of weeklyGroceries is not straightforward, figuring out how it works will deepen your understanding of functional programming. This will empower you to write some things very concisely, such as the definition of sum at the top.

For the convenience of the reader, here are links to the documentation of each Underscore function used in this snippet, by order of evaluation:

_.partial _.reduce _.chain _.map _.keys _.flatten _.uniq _.value _.zip _.object _.mapObject _.property _.partial _.compose _.compact

Upvotes: 1

Peter
Peter

Reputation: 1259

Try this, pure js:

function weeklyGroceries(arr) {
  
  return arr.reduce((acc, curr) => {
    for (const key in curr) {
      if(acc[key]) {
        acc[key] = acc[key] + curr[key];
      } else {
        acc[key] = curr[key];
      }
    }
    return acc;
  }, {});
}

Upvotes: 0

Tomas
Tomas

Reputation: 3436

Using reduce is the very good idea. I guess you were misleaded a bit by reduce signature Consider following:

reduce((accumulator, currentValue) => { /* … */ })

It means, that reduce will work on each iteration with some kind of accumulator (this will carry on sum on each loop iteration) and current value of array, one after another on each iteration.


weeklyGroceries.reduce((acc, currentValue) => {
 return {
   apple: acc.apple + currentValue.apple,
   banana: acc.banana + currentValue.banana,
   fish: acc.fish + currentValue.fish,
   melon: acc.melon + currentValue.melon,
  }
}, {
  apple: 0,
  banana: 0,
  fish: 0,
  melon: 0,
})

If, for some reason, like training or just for fun, you wish to avoid using build-in functions, you can achieve same, by manually iterating over every entry of your object and sum all respective fields:

let sums = {};
Object.keys(weeklyGroceries[0]).forEach(key => {
    console.log(key)
  let partailSum = 0;
  for (let idx = 0; idx < weeklyGroceries.length; idx++) {
    partailSum += weeklyGroceries[idx][key];
  }
  sums[key] = partailSum;
})

Upvotes: 1

Shahzeb Qureshi
Shahzeb Qureshi

Reputation: 612

You can use the _.reduce function from the Underscore library to sum the values of the same items in the array of objects.

Here is an example:

function weeklyGroceries(weeks) {
  return _.reduce(weeks, function(result, week) {
    _.each(week, function(value, key) {
      result[key] = (result[key] || 0) + value;
    });
    return result;
  }, {});
}

Upvotes: 2

Related Questions