1

Why array.reduce returns NaN when I add 3rd object? See example below. What am I missing?

var x =[ 
 {Sum: 1},
 {Sum: 2},
 {Sum: 3}
]; 

var y = x.reduce((total, value) => total.Sum + value.Sum);

console.log(y);  // Why output is NaN?


x =[ 
 {Sum: 1},
 {Sum: 2},
]; 

y = x.reduce((total, value) => total.Sum + value.Sum);

console.log(y); // output = 3
Syed Rafey Husain
  • 153
  • 1
  • 1
  • 7
  • 2
    Because on the second iteration `total` will be just the number `3` and you're getting `3.Sum` which is `undefined`. – VLAZ Apr 13 '20 at 13:57
  • 1
    Because in the second case `.reduce` only iterates once, which does not expose the mistake in your code. The mistake is only visible if `.reduce` iterates at least twice: `a + b` returns a number, which becomes the next value of `total`. And numbers don't have a `Sum` property. – Felix Kling Apr 13 '20 at 13:57

2 Answers2

2

You need either to return the same structure as both items,

var x = [{ Sum: 1 }, { Sum: 2 }, { Sum: 3 }],
    y = x
        .reduce((a, b) => ({ Sum: a.Sum + b.Sum })) // reduce with the same structure
        .Sum;                                       // get value

console.log(y);

or take an initialValue of Array#reduce for reducing, because you add a number and not a property.

var x = [{ Sum: 1 }, { Sum: 2 }, { Sum: 3 }],
    y = x.reduce((total, object) => total + object.Sum, 0); // start with zero

console.log(y);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
2

The reason why your code with 2 objects seems to work, is because when you use the reduce function with no initial value, the accumulator takes the first array value as its initial value, in this case { Sum: 1}. So on the first iteration of your reduce function, total.Sum + value.Sum is 1 + 2, which gives 3. There are no more objects in the array, the iteration ends, and the error is not seen.

However, once you have 3 objects, on the next iteration, your accumulator is no longer in object form, it is now a number (3). You then try to get total.Sum which now is 3.Sum, which means nothing.

For clarity, let's add the initial value of the accumulator as the second argument of your reduce function. Assuming you want a number to represent the total, let's use 0 to start off with.

As you move through the reduce function, you want to add the value of each value.Sum to your total, and then return the total. This should not be total.Sum, since total is not an object.

Here is a working example, with console logs for clarity as to what is happening in the reduce functions:

var x =[ 
 {Sum: 1},
 {Sum: 2},
 {Sum: 3}
]; 

var y = x.reduce((total, value) => {
 console.log('1 -->', total, value);
 return total + value.Sum
}, 0);

console.log('final y value -->', y); 


x =[ 
 {Sum: 1},
 {Sum: 2},
]; 

y = x.reduce((total, value) => {
 console.log('2 -->', total, value);
 return total + value.Sum
}, 0);

console.log('final y value -->', y); 
royranger
  • 384
  • 1
  • 3
  • 10