JavaScript provides many useful functions to loop through an array and execute an operation on each element of the array like forEach, filter, map, reduce, find, some, every and many more.

Filter and map are generally over while forEach and reduce are not only less used but reduce also receives a lot of hate for "making" the code harder to read and not being useful at all.

During my career as a developer I have learned about clever and useful ways of effectively applying reduce and making it an important tool to have in your belt as a programmer. Regardless of the programming language that you use, it is important to learn the tools that your language offers and make them work to solve the problems that you are facing as a programmer.

So my plan with this post is to make a bit of a case for useful ways of applying reduce for solving problems, rather than explaining how reduce works in a totally beginner friendly manner. So if you have any questions feel free to write me on Twitter.

What is reduce anyway?

reduce as all of the other methods mentioned above receives one function which is executed on each element of the array.

In the case of reduce it also receives an initial value which is optional.

reduce(reducerFn) reduce(reducerFn, initialValue)

The function executed for each element is called a reducer and its signature looks like this:

function reducer(accumulator, currentValue) { ... }

The reducer receives 2 more parameters which are optional but in this post we're going to be focusing in the accumulator and currentValue .

So currently we have some terminology that we should care about like:

  • initial value: The value used to initialize the accumulator. It could be a Number, a String, an Array or any other data type.
  • reducer: the function that we execute on each element of the array.
  • accumulator: the value we end up with, after executing the reducer.
  • current value: the value we are processing during the iteration of the array.

This terminology already gives us some insight of how reduce works.

A replacement for map and filter

We have an accumulator as the value we will receive at the end of the reduce execution and we have access to it in the reducer the function that is execute on each element of the array. This means we have full control of what actually goes in the accumulator and it could be a totally different data structure from the one we started with in the array, giving us the ability to construct the signature of the data as we want it just like map does but unlike map we can decide to populate this accumulator with data based on conditionals just like filter does.

So essentially if you have to do filtering and mapping of your data, using reduce is a better option that the commonly used:

arr.filter(filterFn).map(mapFn)

You can use reduce and iterate the array only once.

For example if we have this comma separated file:

1,Wynton Kelly,piano
2,John Coltrane,saxophone
3,Miles Davis,trumpet
4,Herbie Hancock,piano
5,Bill Evans,piano
6,Oscar Peterson,piano

we want to read it line by line and store it in an array of objects but only when the instrument is piano we could use map and filter for this:

const procesed_map_filter = musicians.map((line) => { const musician = line.split(',') return({ id: musician[0], name: musician[1], instrument: musician[2] }) }).filter((musician) => musician.instrument === 'piano')

We use map to transform the array of strings into an array of objects with the interface we specified for our data and we use filter to select only the musicians that play the piano. This two functions execute independently of each other and they both iterate over an array one after the other.

We could solve the same problem with a reducer iterating only once over the array and doing the map and filter inside of the reducer function :

const reducerFn = (accumulator, currentValue) => { const musician = currentValue.split(',') if(musician[2] === 'piano') { // we filter accumulator.push({ // and we map id: musician[0], name: musician[1], instrument: musician[2] }) } return accumulator } const initialValue = [] const procesed_reduce = musicians.reduce(reducerFn, initialValue)

It might look like a bit more code but I made it explicitly verbose with the variable declarations so we could see the important terminology. So we could reduce haha its footprint more if we inline the reducer function and the initialValue like we did with the map and filter. And we are also iterating over the array only once.

Both produce the same data structure:

[ { id: '1', name: 'Wynton Kelly', instrument: 'piano' }, { id: '4', name: 'Herbie Hancock', instrument: 'piano' }, { id: '5', name: 'Bill Evans', instrument: 'piano' }, { id: '6', name: 'Oscar Peterson', instrument: 'piano' } ]

Other reduce uses

My plan is to keep this posts short so this is part 1 and other parts will come soon with examples of other scenarios where reduce can be a better option and what other options we could have if we still don't want to use reduce.