How to use JavaScript's Reduce

Boston Cartwright | January 22, 2021
5 min read | ––– views
Photo by Roy Perez on Unsplash

When I first started learning and working in JavaScript, I came from an OOP background. I liked working in classes and working with well known design patterns. However, I quickly realized the power of functional programming when I started working with JavaScript's array functions.

The first thing to understand when working in a functional language is that functions are things. Just like integers, strings, and all other types, functions fit that category.

This is important because it allows us to pass functons as parameters into other functions, which are typically referred to as callbacks.


If we look at MDN's documentation for the reduce method, we see it defines it as:

The reduce() method executes a reducer function (that you provide) on each element of the array, resulting in single output value.

It then provides the following example:

const array1 = [1, 2, 3, 4]
const reducer = (accumulator, currentValue) => accumulator + currentValue
// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer))
// expected output: 10
// 5 + 1 + 2 + 3 + 4
console.log(array1.reduce(reducer, 5))
// expected output: 15

When I first saw this, it did not make much sense to me. If you feel the same, hopefully this article will help clear it up for you.


Let's take a very simple example here. You have two functions:

function Product(n) {
let product = 1
for (let i = 1; i <= n; i++) {
product *= i
}
return product
}
function Sum(n) {
let sum = 0
for (let i = 1; i <= n; i++) {
sum += i
}
return sum
}
console.log(Product(5))
// expected output: 120
console.log(Sum(5))
// expected output: 15

These are two very simple functions, the first giving you the product of every number from 1 to the number you provide (n). The second gives you the sum of every number from 1 to the number you provide (n).

After you write these two functions, you notice that they share some code and being a good programmer, you want to reduce duplicated code.

Don't repeat yourself!

function Product(n) {
let product = 1
for (let i = 1; i <= n; i++) {
product *= i
}
return product
}
function Sum(n) {
let sum = 0
for (let i = 1; i <= n; i++) {
sum += i
}
return sum
}

However, it is easy to see that these two functions are actually very similar. They share three main parts, an initial value (highlighted in red), common code (the loop) (highlighted in blue), and an action (highlighted in orange).

function Product(n) {
let product = 1
for (let i = 1; i <= n; i++) {
product *= i
}
return product
}
function Sum(n) {
let sum = 0
for (let i = 1; i <= n; i++) {
sum += i
}
return sum
}

First, you might consider refactoring it like this:

function BasicReduce(n, action, initialValue) {
let final = initialValue
for (let i = 1; i <= n; i++) {
final = action(final, i)
}
return final
}
function Product(n) {
function productAction(accumulator, currentValue) {
return accumulator * currentValue
}
return BasicReduce(n, productAction, 1)
}
function Sum(n) {
function sumAction(accumulator, currentValue) {
return accumulator + currentValue
}
return BasicReduce(n, sumAction, 0)
}

And this works! You have now written your own basic reduce function.

However, this will only work on numbers leading up to a top value. Let's look into how we can change this to work off of an array.

function FinalReduce(arr, action, initialValue) {
let final = initialValue
for (let element of arr) {
final = action(final, element)
}
return final
}

Awesome! Now let's update our math functions to work with this.

function Product(n) {
function productAction(accumulator, currentValue) {
return accumulator * currentValue
}
// create a new array from 1 to n
// read more about this function here:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from#using_arrow_functions_and_array.from
const arr = Array.from({ length: n }, (v, i) => i + 1)
// ends up looking like this when n is 5: [1, 2, 3, 4, 5]
return FinalReduce(arr, productAction, 1)
}
function Sum(n) {
function sumAction(accumulator, currentValue) {
return accumulator + currentValue
}
// create a new array from 1 to n
const arr = Array.from({ length: n }, (v, i) => i + 1)
// ends up looking like this when n is 5: [1, 2, 3, 4, 5]
return FinalReduce(arr, sumAction, 0)
}

And that's it, we recreated reduce ourselves!

We could even further refactor our Product and Sum functions to use inline arrow functions like so:

const Product = (n) =>
FinalReduce(
Array.from({ length: n }, (v, i) => i + 1),
(a, c) => a * c,
1
)
const Sum = (n) =>
FinalReduce(
Array.from({ length: n }, (v, i) => i + 1),
(a, c) => a + c,
0
)

Notice we are no longer referencing these as Functions, but as consts, because functions are things that can be assigned to variables!

Here is the same functions but using JavaScript's reduce:

const Product = (n) =>
Array.from({ length: n }, (v, i) => i + 1).reduce((a, c) => a * c, 1)
const Sum = (n) =>
Array.from({ length: n }, (v, i) => i + 1).reduce((a, c) => a + c, 0)

I hope this article helped you to understand the reduce function a little better and it's purpose.

What do you think? Let me know on Twitter @bstncartwright 😃