Reduce returning undefined?

To add to Ethan's sufficient explanation of reduce you might also consider a map into the appropriate format for reduction into a single value.

students.map( student => student.score ).reduce( (a, b) => a + b, 0 );

There is nothing wrong with your code that a little debugging could not help with. Place a breakpoint on the return statement. When the engine stops there, examine the values of a and b. Alternatively, as a commenter suggested, you could add a console.log line there, to output the values to the console. In either case, you will see that they are the first two values in the array--this is how reduce behaves if you fail to give it the second parameter. The returned value will be {sum: students[0].score + students[1].score}. Now continue execution. You will break again at the return statement; examine a and b again. You will see that a is not a student, nor a number, but rather the {sum: } object you returned on the previous iteration, which has no score property. Assuming the sum of the first two scores was 192, the next return value will thus be {sum: {sum: 192}.score + students[2].score}. That turns into {sum: undefined + students[2].score}, which in turn becomes NaN, since adding anything to undefined returns NaN. Things now go downhill from there.

When you discover that the second time through the loop, a is {sum: 192}, you should realize that that is neither a student whose score you can take, nor a value you can add something to. With a little additional reading of the reduce documentation, and perhaps looking at a few examples, you should be able to figure out that you need to return the sum itself, not an object containing a property sum. That sum will then become the a in the next iteration of the loop. To make this work, you'll need to give reduce an initial value of 0 as its second parameter.

As you move ahead on your programming journey, you'll run into many such bumps in the road. Unfortunately, you cannot depend on SO people to solve all of them for you, and even if they do, you could remain stuck for hours or days until they answer. You really need to learn how to pin down and solve such problems for yourself. The debugger is key to doing that, so there is no alternative to learning how to bring it up, set breakpoints, and examine variables. Take a few hours out of your schedule and read through the docs carefully. You can find them at https://developers.google.com/web/tools/chrome-devtools/. Here is a good overview how to debug small programs; http://ericlippert.com/2014/03/05/how-to-debug-small-programs/.


I think you have a misunderstanding about how reduce works. For each element in the array, it executes the provided function. The first argument is an "accumulator"; something that's passed along as each element is visited (actually, it's the return value of the function from the last element, but it's usually used as an accumulator). The second argument is the element being visited. So what I think you want is this:

var sum = students.reduce(function(a, s) {
    a.sum += s.score;
    return a;
}, { sum: 0 });

When you invoke reduce, you can provide the initial value of the accumulator (otherwise it takes on the value of the first element, and the visitation starts with the second element). Here, we provide an object with a sum property set to zero.

If all you want is the sum (not an object with a sum property), it can be even simpler:

var sum = students.reduce(function(a, s) {
    return a += s.score;
}, 0);

Tags:

Javascript