Javascript Array Reduce Method

Johnny Simpson - Oct 16 '22 - - Dev Community

The Javascript reduce method is a recursive way to perform a computation based on every element in array, while also taking into consideration the previous element in the array. It accepts a function, which can also be used to further process elements of the array based on logic of your choosing.

It is quite useful for summing arrays, or merging string based arrays. For example, we could turn an array into a string like this:

let myArray = [ 'hello', 'world', 'welcome!' ]

let reduceString = myArray.reduce((previousElement, currentElement) => {
    return `${previousElement} ${currentElement}`;
})

console.log(reduceString); // hello world welcome!
Enter fullscreen mode Exit fullscreen mode

In a similar vein, we could use it to add up all the numbers in an array and return a single number:

let myArray = [ 5, 10, 15, 20 ]

let reduceString = myArray.reduce((previousElement, currentElement) => previousElement + currentElement)

console.log(reduceString); // 50
Enter fullscreen mode Exit fullscreen mode

The reduce method callback function

The callback function used in reduce actually has 4 arguments. You are not required to use any, but the first two are the two you will usually want. The format of the function looks like this:

Array.reduce((previousElement, currentElement, currentIndex, array) => {
    // Do something with the array's data
}, initialValue)
Enter fullscreen mode Exit fullscreen mode

Let's look at what previousElement, currentElement, currentIndex, array and initialValue all mean.

previousElement

This is self explanatory. It represents the previous element from the current one we are iterating through. The reduce function will usually start at the index [1], so that a previous element does exist. If you have defined an initialValue, then this value will be used and the reduce function will begin at index [0], using the initialValue as the previousValue.

currentElement

This is the current element that is being iterated through by reduce.

currentIndex

Since arrays don't consist of just indexes, and often have useful data in them, we also have the ability to get the current index being iterated through. This will return the 0 indexed number representing the current element's position in the array. Expect standard array indexes from this argument.

array

This will return the entire array - which can be useful if you plan to manipulate the array using reduce, or, if you want to compute based on other elements in the array

initialValue

If provided, this will be the previousElement for index [0].

As mentioned, this are all optional, but they all provide a useful way to manipulate and calculate the return value for your reduce method.

Mutating the Array in reduce

If you try to mutate the array in reduce, it could lead to some interesting behaviour - so there are a few edge cases you should consider when thinking about reduce.

For example, if you change an array element somewhere ahead of your current element, the reduction will still work as expected. For example, adding 1000 to myArray[currentIndex + 1] will still produce the expected value:

let myArray = [ 4, 5, 6, 7, 8 ]
let reduceFunction = myArray.reduce((prevValue, currentValue, currentIndex) => {
    myArray[currentIndex + 1] += 1000
    return prevValue + currentValue
});
console.log(reduceFunction); // 3030
Enter fullscreen mode Exit fullscreen mode

However, trying to add values to an array while running reduce will not work. For example, below I use push to add one element to the array for each element in the array. This would of course lead to an infinite loop, so Javascript arrests the function and only processes the values that were in the array at the point when we ran reduce:

let myArray = [ 4, 5, 6, 7, 8 ]
let reduceFunction = myArray.reduce((prevValue, currentValue, currentIndex) => {
    myArray.push(1000)
    return prevValue + currentValue
});
console.log(reduceFunction); // 30
Enter fullscreen mode Exit fullscreen mode

Note on Single Value Arrays

If your array only contains one value and you don't use initialValue, the reduce function will return the single value from that array, and not call the callback function. For example:

let myArray = [ 'cat' ]
let reduceFunction = myArray.reduce((prevValue, currentValue) => {
    return currentValue + '!'
});
console.log(reduceFunction); // cat (does not have exclamation mark, even though we tried to add it)
Enter fullscreen mode Exit fullscreen mode

Summing and Combining Values in an Object Array

You might have already expected this behaviour, but if you have an array of objects, you can reference the child properties of each elements object to make calculations. For example, to add up all the ages below:

let myArray = [ { age: 52 }, { age: 34 }, { age: 104 }, { age: 29 } ]
let reduceFunction = myArray.reduce((prevValue, currentValue) => {
    return prevValue + currentValue.age
}, 0);
console.log(reduceFunction); // 219
Enter fullscreen mode Exit fullscreen mode

You might've noticed a few weird things here, which is why it's useful to work through this example:

  • We have to define an initialValue, since initially, prevValue is { age: 52 }, but afterwards, prevValue is a number. That means we keep types consistent.
  • Since every time we run reduce, it returns the a value for the current item in the array element, we use prevValue rather than prevValue.age. prevValue.age is undefined, since reduce returns a number each time.

Conclusion

The reduce method is a really useful way to combine everything in an array, or produce new arrays of your choosing. It's powerful, and recursive - so be careful when using it on large data sets. If you liked this, I also wrote an article here on the slice method.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .