DEV Community

Cover image for Why .reduce() caused me so much confusion over the past 2 days.
Lost Semicolon πŸ’»πŸ–±
Lost Semicolon πŸ’»πŸ–±

Posted on • Edited on

Why .reduce() caused me so much confusion over the past 2 days.

This month I started doing coding katas to improve my JavaScript skills. I do puzzles and quizzes on my phone a lot anyway, and coding is not that far off solving puzzles.

I am using Code Wars - the site is free, you can see other folks' solutions and there is a level system to see you progress. It also encourages you to participate in the community, which is a great mindset to install in people.

I found it to be a great tool, even though the interface can be a lot and I had to familiarise myself with the ranks.

I was doing a simple kata of adding arrays. The kata requested that, given an array of items, I had to return a sum of all positive values in the array.

Initially, and I thought that adding all items in the array would be an easy task, as this can be done using the .reduce() function. But not all of the tests were passing.

function positiveSum(arr) {
  return arr.length > 0 ? arr.reduce(addAll) : value;
}

function addAll(total, value) {
  return value > 0 ?  total + value : total;
}

When the input arrays started with a negative values, my tests failed. In a test where an array had all negative values, I would expect the value of 0 to be returned as no values would be added. However, I would be finishing up with the arr[0] value instead.

Unfortunately, I have wrongly assumed that the total value (also known in js land as the accumulator) started at 0. This is not the case - the accumulator starts as the first value in the array. AND the first loop starts on the 2nd item in the array (arr[1]). For example:

function positiveSum(arr) {
  return arr.length > 0 ? arr.reduce(addAll) : value; 
}

function addAll(total, value) {
  console.log('Total is ' + total + ' and current value is ' + 
  value) 
  return value > 0 ?  total + value : total;
}

let testArray = [-1,-2,-3,-4,-5]; //we expect 0 as all are negative values

positiveSum(testArray); //we get -1

//Output
//Total is -1 and current value is -2
//Total is -1 and current value is -3
//Total is -1 and current value is -4
//Total is -1 and current value is -5

So, as you can see, the function is only called 4 times, with -1 being the initial accumulator value. This meant that the arrays which were starting with a negative value, would have incorrect totals.

In addition to the above, when arrays were empty, I had to put in a safety check for that as well.

Defeated, I have used a simple .forEach() to finish my kata - which, admittedly, worked like a charm.

BUT PLOT TWIST!

When I have looked at solutions for my fellow coders, I have realised that .reduce() method can, in fact, take an initial accumulator value!

The only thing I had to correct was adding a 0 as an argument in my reduce() function :

 return arr.reduce(addAll,0);

What does this do to iterations? Well, there is now an iteration per element in the array, starting at the 1st element (arr[0]).

The problem of reductions on empty arrays was also solved this way!

The final solution is as follows:

function positiveSum(arr) {
  return arr.reduce(addAll, 0); 
}

function addAll(total, value) {
  return value > 0 ?  total + value : total;
}

So moral of the story is.... Always look for improvements to your solutions :)

Doc

MDN docs

Top comments (0)