We will create the king item

Understanding Javascript .reduce() and its use cases

Wisani Shilumani
Nona Digital
Published in
4 min readJan 14, 2019

--

In this article, we’ll explore how the JavaScript Array .reduce() method works, and some powerful use cases for it.

First, what is it?

The reason I could never wrap my head around this method was failing to understand the word ‘reduce’, Oxford’s definition is:

To make smaller or less in amount, degree, or size.

This is exactly what the reduce function does. It iterates over an array (a group of elements of the same type — ideally) from left to right, and reduces it to a single value.

  • Note: the single value could be an object or any primitive type.

The easiest explanation

Imagine an array of numbers:

If we wanted to add all the numbers in the array, we could use a forEach loop:

The forEach method iterates from left to right, starting at 101.2 and adding it to 0; then over 242.2, adding it to 101.2 etc…

The reduce method equivalent, which doesn’t have the messy predefined variable spill over let total = 0would be:

Here, the reduce method is applied to the numbersToSum array, upon each iteration — we add the currentNumber that’s being looped over to the currentTotal (the current total defaults to 0 in the initial iteration — sort of, explained later).

This happens for every item in the numbersToSum array, until our total is the sum of all the entries in the numbersToSum array.

How it works

The reduce method takes in 2 parameters.

First — a callback function that accepts up to four parameters (all optional), namely the:

  1. previousValue: Whatever the previous iteration returned
  2. currentValue: The current value in the array that’s being iterated over
  3. currentIndex: The index of the current value
  4. array: The array being iterated over

As the method iterates over the array elements, it allows you to manipulate the previousValue that will be received by the next iteration. In other words, if we ran:

[1, 2, 3].reduce((previousValue, currentValue) => previousValue + currentValue) 

For explanations sake: In the first iteration, we return 0 + 1 , in the second iteration, our previousValue now equals to 1, and we add it to 2 to alter the next previousValue. In our last iteration our previousValue is 3, we add it to our currentValue of 3 and the reduce method returns a value of 6, the expected total.

The second parameter, following the 4-param callback, is the initialValue, all this does is it sets the previousValue used in the first iteration.

The clever actuality:

If you’ve worked with reduce a few times, you’ll know that the reduce function only iterates twice over the [1, 2, 3] array. It does this for 2 clever reasons:

First, it reduces the iteration count. If it assumes 1 as the initialValue , this is the same as having the first iteration returning 0 + 1, so we can correctly skip the first, 0 + 1, iteration. The first iteration would then be looking at 2 and adding an initialValue of 1 to it.

Second is typing; because the reduce function can return a single value of any type, assuming the type of element it’s working with using the first entry of the array makes its life easier. On it’s first iteration, if we’re adding an element to some initial value, if the values are not of the same type, it can get messy — see below:

0 + {} !== {} + 00 + {} // returns "0[object Object]"
{} + 0 // returns 0

If we were to initialise our reduce with an object instead, forcing 3 iterations:

[1, 2, 3].reduce((total, number) => total + number, {})// it would return "[object Object]123"
// yuck

When is it used?

If you were to reduce everyone’s use cases for the `reduce` function, it would be that:

The single use case for the `reduce` function is to create clusters of data.

Use case examples

Single cluster: Sum of numbers in an array

[1, 2, 3].reduce((total, number) => total + number)// returns 6

Single cluster: Averaging numbers in an array

[1, 2, 3].reduce((total, number, index, array) => {
total += number // add current number to total

if (index === array.length - 1) { // if we're at the last iter.
return total/array.length // return the average
}
return total
})
// returns 2 (= 6 / 3)

Single cluster: Flatten array

Say you had an array of blog articles, each containing an array of comments. If you wanted to get a list of all comments, you could use the reduce function:

An array is a single value (They’re actually JS Objects in an array’s clothing)

Multiple clusters: Tally of items

Say we had an array of strings describing fruit:

If we wanted to return an object that would give us a tally of each fruit in the array (not knowing what fruit could possibly be in the array — hence we couldn’t use .filter())

We could simply write:

const fruitTally = fruit.reduce((currentTally, currentFruit) => {
currentTally[currentFruit] = (currentTally[currentFruit] || 0) + 1
return currentTally
} , {})
// returns {"apple":3,"banana":3,"cherry":2,"mango":2,"apricot":1,"guava":2}

Multiple clusters: Date categorisation

This is perhaps my favourite use case. Say you have a list of a users’ transactions with Unix timestamps and you wanted to group them by month (so a user could open one month, and close the others for better UX)

As it currently stands, the data is too flat to represent in any user friendly way, this could be an array of 1000 entries. We can categorise it neatly using a reducer:

We’re essentially converting an array to an object with our own rules

Conclusion

The .reduce()function allows us to do some pretty neat data manipulation. It really shines when it comes to making data easier to work with, or easier to represent where it needs to be read by humans.

--

--

Wisani Shilumani
Nona Digital

Hi! I’m Wisani, a software developer at Allan Gray at the V&A Waterfront. I love building tech that inspires.