Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reduce array of object to totals by property object

I'm looking for a smart ES6 way to reduce array of objects into totals-by-property-object.

for a sample data:

const src = [{mon:1,tue:0,wed:3,thu:5,fri:7,sat:0,sun:4}, {mon:5,tue:3,wed:2,thu:0,fri:1,sat:0,sun:6}];

following code:

const res = src.reduce((totals,item) => Object.keys(item).forEach(weekday => totals[weekday] += item[weekday]),{})

throws an error:

Uncaught TypeError: Cannot read property 'mon' of undefined

even if reduce is initialized with {mon:0, tue:0 ...} instead of {}.

Is there a non-for-loop solution?

p.s. expected output is an object where each property is a sum of array objects by that property, e.g. {mon:6, tue:3, wed:5, thu:5, fri:8, sat:0, sun:10} in my case

like image 409
user11154868 Avatar asked Mar 29 '19 13:03

user11154868


People also ask

How do you call reduce on an array of objects to sum their properties?

const sum = values. reduce((accumulator, currentValue) => { return accumulator + currentValue; } , 0); As you can see, the reduce method executes the call back function multiple times. For each time, it takes the current value of the item in the array and sum with the accumulator.

Can I use reduce on an array of objects?

If you use array reduce on an array without any elements and don't provide initialValue, it will throw a TypeError. If the array is empty and initialValue is provided, or the array has only one element and initialValue, the reduce method will return the same value without calling the callbackfn.

How do you get the sum of a property in an array of objects?

To sum a property in an array of objects:Call the reduce() method to iterate over the array. On each iteration increment the sum with the specific value. The result will contain the sum of the values for the specific property.

Does reduce work on object?

But did you know you can reduce them to objects as well? First, a quick overview of how reduce works. The reduce method receives two arguments: a function and an initial value. The function will run run for every value in the array, and receives two arguments as well: the accumulator, or acc , and the current value .


2 Answers

You need to return totals as accumulator for reduce.

If you have allways all days in the objects and you don't mind to mutate the first object, you could work without a start object.

const
    src = [{ mon: 1, tue: 0, wed: 3, thu: 5, fri: 7, sat: 0, sun: 4 }, { mon: 5, tue: 3, wed: 2, thu: 0, fri: 1, sat: 0, sun: 6 }],
    res = src.reduce((totals, item) => 
        (Object.keys(item).forEach(d => totals[d] += item[d]), totals));

console.log(res);
like image 22
Nina Scholz Avatar answered Oct 26 '22 09:10

Nina Scholz


You need to return totals after you modify it:

const src = [{mon:1,tue:0,wed:3,thu:5,fri:7,sat:0,sun:4}, {mon:5,tue:3,wed:2,thu:0,fri:1,sat:0,sun:6}];

const res = src.reduce((totals, item) => {
  Object.keys(item).forEach(weekday => totals[weekday] = (totals[weekday] || 0) + item[weekday]);
  
  return totals;
}, {});

console.log(res);
like image 93
Ori Drori Avatar answered Oct 26 '22 07:10

Ori Drori