simeonGriggs.dev
Twitter
GitHub

Understanding reduce() as a combination of map() and filter()

It can be tough to identify use cases for something like reduce() until you’re already comfortable using it. Consider this a gentle entry point on your path to advanced use of the Swiss Army Knife of Array Methods.

View in Sanity Studio

2022-03-07

Getting an understanding of Array Methods is key to feeling increasingly confident writing JavaScript. The most powerful – and therefore most complex – is reduce()

I never found it helpful to try and understand reduce() reading explainers like “reduce can take an array and return anything”. What?

That’s true – but when starting it's likely more mental overhead than you need.

In this article we’ll look at reduce() for a simple use case – taking an array and returning an array. That’s what map() and filter() do, and hopefully you're already comfortable with those.

Mapping and filtering

Imagine we have an array of numbers, and we need to increase every score by 1 and eliminate any scores now over 5.

const scores = [1, 5, 4, 3, 2]
// map() modifies every element in the array
// "Increase every score by 1"
const scoresMapped = scores
.map((item) => item + 1))
// returns [2, 6, 5, 4, 3]
// filter() removes elements from an array
// "Only return scores below 6"
const scoresFiltered = scoresMapped
.filter((item) => item < 6)
// returns [2, 5, 4, 3]

The above illustration performs map() and filter() separately in their own variables. But it’s possible to chain the methods and get the same result stored in one variable.

// "Increase every score by 1, but only return scores below 6"
const scoresMappedandFiltered = scores
.map((item) => item + 1))
.filter((item) => item < 6)
// returns [2, 5, 4, 3]

Make no mistake: There’s nothing “wrong” with chaining Array Methods – and you could argue they’re easier to read than the code below – but it presents us an opportunity to perform a very simple reduce(). So let’s do it!

Reducing

When using map() and filter() our logic is only concerned with each individual item in the array.

With reduce() we get access to the individual item as well as the entire array during each iteration. This means we can modify each item as well as selectively add to the array with each iteration.

Consider these differences:

  • In map() we return an updated item
  • In filter() we return a boolean to include/exclude that item
  • In reduce() we return the latest value of the entire array
// "output" below is often written as "previousValue", "acc" or "accumulator"
// It's the final value that will be returned by .reduce()
const scoresReduced = scores.reduce((output, item) => {
// Like map(), modify the item this iteration
const itemIncreased = item + 1
// Like filter(), choose whether this item is in the final array
return itemIncreased < 6
? [...output, itemIncreased]
: output
// 👇 The initial value for "output"
}, [])

The second parameter ([] on the last line) is the default value for output. In this instance, an empty array.

This second parameter can be anything, and what you return inside of the reduce can be anything. This is the confusing part I'm deliberately avoiding in this particular article. Once you're more comfortable with reduce() you'll find reasons to use.

For example instead of returning an array, you could return a number like the average of all scores under 6.