Array.prototype.reduce()

Zoe Friedman
4 min readOct 10, 2021

--

Array.prototype.reduce() may seem scary and intimidating at first, but I encourage you to steel yourself and go for it! It’s a game changer:

The reduce() method executes a user-supplied “reducer” callback function on each element of the array, passing in the return value from the calculation on the preceding element. The final result of running the reducer across all elements of the array is a single value. — MDN

Something about the MDN docs did not do it for me at first. It took a deeper dive and some practice for me to get a firm grasp. Hopefully my breakdown can save others some time:

The Reducer

Imagine an extreme robot called “THE REDUCER.” You don’t yet know the mechanics inside, but suffice to say it’s going to crush every piece of your sad little array into a single pathetic unit it will then spit out at the end, completely transformed. TOUGHEN UP, NERD!

SO! WHAT ARE THE ARGUMENTS?

There are a few different ways of using arguments here and how they are fed in depends on the syntax you’re using. Let’s start with an arrow function. Here the MDN docs come in super handy. Here are the arguments if you’re using an arrow function:

reduce((previousValue, currentValue) => { ... } )
reduce((previousValue, currentValue, currentIndex) => { ... } )
reduce((previousValue, currentValue, currentIndex, array) => { ... } )
reduce((previousValue, currentValue, currentIndex, array) => { ... }, initialValue)

Let’s look at that first, most basic version via the example of just adding all the elements of an array together and reducing them down to a single value. I personally prefer to use an abbreviated term for “accumulator” rather than the lengthy “previousValue.”

“acc” will represent what we are adding to every time, while “curr” is short for “current.” We are going through our array and adding the current value to our accumulator via our callback function:

let array1 = [1, 2, 3, 4]
array1.reduce((acc, curr) => acc + curr))
// 10

NOTE: If you do not specific the initial value after you lay out your callback function, your accumulator will be initialized with the first element in your array! So when .reduce() sees we did not specify the initial value, it then set it equal to 1!

Let’s see a specified initial value in in action. Say we’re talking $$ and I started out with a big ol’ Franklin:

let array1 = [1, 2, 3, 4]
array1.reduce((acc, curr) => acc + curr, 100)
// 110

Now as for the arguments, I don’t have great ideas for use cases utilizing the current indexes or the array arguments, but I find them super helpful during debugging. Here, have a look at an example I worked with recently. If the number in the array is greater than zero we are tallying it, if it is less than zero, we are adding it together:

function countPostivesSumNegatives(input){
return input.reduce((acc, curr, index) => {
debugger
return (curr > 0) ? [acc[0] + 1, acc[1]] : [acc[0], acc[1] + curr]
}, [0, 0])
}
countPositivesSumNegatives([1,2,3,-5,-9])
// [ 3, -14 ]

I was having a bit of a trouble understanding what the hell was going on here—so you can see I added in a debugger. I included the third “index” argument to allow myself to track where we were in the array! Once my debugger hit, I was able to see where we were as we moved through the function. Note here also that we are dividing our initial value into two separate components to keep track of two elements. Very cool!

Alternative syntaxes

MDN likes to isolate their callback function that they then pass into their reducer.

const array1 = [1, 2, 3, 4];
const reducer = (previousValue, currentValue) => previousValue + currentValue;
console.log(array1.reduce(reducer));

Or if you’re starting with an initial value, like with our $100 bill:

console.log(array1.reduce(reducer, 100));

I find that syntax a little redundant and confusing. But I can imagine scenarios in which it would be useful. You can also view it inline here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce#syntax

Here are two alternative syntactical versions of flattening an array:

My arrow function version:

let array1 = [[0, 1], [2, 3], [4, 5]]
array1.reduce((acc, curr) => acc.concat(curr))

via MDN inline:

let flattened = [[0, 1], [2, 3], [4, 5]].reduce(
function(previousValue, currentValue) {
return previousValue.concat(currentValue)
},
[]
)
// flattened is [0, 1, 2, 3, 4, 5]

Using .reduce to replace .map and .filter

Imagine a scenario in which you would be using .map and .filter together. You’d be traversing the array twice. MDN uses the example of doubling all of the positive numbers in an array but does not show it. Here:

console.log(numbers.filter(num => num > 0).map(num => num * 2))
// [12, 4]

Earn brownie points on your next technical assessment with this time optimization swap—Set up a conditional in your .reduce() function and set the initial value to be an empty array. If the current value satisfies the conditional statement, push it in:

Using.reduce()

const numbers = [-5, 6, 2, 0,];const doubledPositiveNumbers = numbers.reduce((acc, curr) => {
if (curr > 0) {
const doubled = curr * 2;
acc.push(doubled);
}
return acc;
}, []);
console.log(doubledPositiveNumbers); // [12, 4]
”REDUCER” is actually “Behemoth”

--

--