How To Start Using .map() .filter() and .reduce()

An explanation that doesn’t assume you‘re a developer

Jonathan Hsu
Dec 9, 2019 · 4 min read
Photo by Helloquence on Unsplash

When I learned how to use .map(), .filter(), and .reduce() everything I read, watched, and heard sounded so complicated. These concepts were being taught as standalone implementations that I couldn’t wrap my head around.

I heard that these were gateway concepts symbolizing an ascension into enlightenment. I wish I had been told the truth: That these three methods are recognition—and implementation—that the reason you loop through an iterable often falls into one of three functional categories.

Reviewing my previously written code, I realized that 95% of the time when looping through strings or arrays I do one of the following: map a sequence of statements to each value, filter values that meet a specific criteria, or reduce the data set to a single aggregate value.

This was my breakthrough moment. Map, filter, and reduce each simply perform one of these tasks!

To practice, I took my old code and refactored it using these methods. That was supremely helpful.

So without further ado, let’s get on with it. We’ll explain each method then convert common for loop implementations to their respective method.


Map

The .map() method is used when you want to 1. perform a set of statements with every value in the iterable and 2. return the (presumably) modified value.

Let’s use a simple example of calculating sales tax on an array of prices.

const prices = [19.99, 4.95, 25, 3.50];
let new_prices = [];
for(let i=0; i < prices.length; i++) {
new_prices.push(prices[i] * 1.06);
}

We can achieve the same results using .map():

const prices = [19.99, 4.95, 25, 3.50];let new_prices = prices.map(price => price * 1.06);

The syntax above is condensed so let’s walk through it a bit. The .map() method takes a callback, which can be thought of as a function. That’s what is between the parentheses.

The variable price is the name that will be used to identify each value. Since there’s only one input, we can omit the usual parentheses around the parameters.

The statement after the arrow => is the body of our callback. Since the body has only one statement, we can omit the curly braces as well as the return keyword.

Just in case this is still confusing, let’s write it out fully for reference:

const prices = [19.99, 4.95, 25, 3.50];let new_prices = prices.map((price) => {
return price * 1.06
});

Filter

On to the .filter() method, which is used when you want to extract a subset of values from the iterable. When using .filter(), remember that we are filtering in values, not filtering out. This means that each item in the iterable that evaluates true will be included in the filter.

Let’s use an example of keeping only odd integers. We’re using the modulus operator to calculate the remainder of dividing by 2. When that remainder equals 1, we know the number was odd.

const numbers = [1,2,3,4,5,6,7,8];
let odds = [];
for(let i=0; i < numbers.length; i++) {
if(numbers[i] % 2 == 1) {
odds.push(numbers[i]);
}
}

Similar to the .map() method, .filter() accepts a single callback to where each value in the iterable will be passed.

const numbers = [1,2,3,4,5,6,7,8];let odds = numbers.filter(num => num % 2);

Similar rules apply for this callback. Since there’s a single input, and the body of the function is a single expression, we can omit the parameter list parentheses, the curly braces defining the body, and the return keyword.


Reduce

Finally, we come to .reduce(), which, admittedly, is the most confusing of the three methods. The name of the method refers to reducing multiple values to one. However, I found that it’s easier to think of it as building up rather than reducing.

The method works by defining a starting point. As the method iterates over each value, that starting point is modified and passed down.

Here’s a classic case of adding a series of numbers together. Pretend we’re calculating the total donations to your favorite charity:

const donations = [5, 20, 100, 80, 75];
let total = 0;
for(let i=0; i < donations.length; i++) {
total += donations[i];
}

Unlike .map() and .filter(), the .reduce() method’s callback requires two parameters: an accumulator and the current value. The accumulator will be the first parameter and is the “pass it down” value.

const donations = [5, 20, 100, 80, 75];let total = donations.reduce((total,donation) => {
return total + donation;
});

We could also pass a second argument to the .reduce() method itself. This would serve as the starting value for the accumulator. Let’s say we’re adding yesterday’s donations that totaled $450.

const donations = [5, 20, 100, 80, 75];let total = donations.reduce((total,donation) => {
return total + donation;
}, 450);

There you have it. These methods are not scary! Think of them as making your code more readable. You are writing more condensed code, but more importantly, you are actually describing the intention of your loop.

You’ll have a much easier time reading your code when you look back at it in three months. Instead of having to read the statements within the for loop, just to understand its high-level intention, you can see map/filter/reduce and begin to have an idea about what the block is trying to achieve.

Better Programming

Advice for programmers.

Jonathan Hsu

Written by

I’m a black belt problem-solver (literally). I enjoy the taking on new challenges, building skills, and sharing what I’ve learned. 🥋

Better Programming

Advice for programmers.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade