How To

JavaScript map, reduce and filter for beginners

6 Oct , 2017  

JavaScript Array FunctionsHere’s the thing: I really don’t think map, reduce and filter are for beginner programmers.

Not because they’re “hard” or “too much” for beginners.

Just because they make an “obvious”1 operation less obvious. Once we’re familiar with these functions it’s easy to take what they do for granted.

Yet I see beginner programmers pushed towards JavaScript Array functions like map, reduce and filter.

Often it’s because someone asks why their for loop isn’t working, and they’re answered with “Just use Array.map”, along with a working example.

The person asking the question can see that the Array.map solution works, but they can’t see why.

And they still haven’t learnt anything about their for loop.

So if that’s you, and you’d like to know more about how map, reduce, etc work, this article is for you.

Reduce: we start with a loop

Before we do anything else, I’ll start with the use-case that gave birth to reduce (spoiler: you want to reduce a list of thing to a single value).

Let’s imagine we have an array, and we want to add all the elements in the array together:

JS Bin on jsbin.com

That’s ok, but we might like to do that more than once, right? So let’s make a function out of it:

JS Bin on jsbin.com

Now we can use our function to repeatedly add numbers in arrays together2. Now we can add like maniacs all through our code.

But now we need to multiply all the values in an array as well. Okaaay.

The natural next action is to reproduce the sumArray with a different name, and swap the += with *=.

Easy right? It could look like this:

JS Bin on jsbin.com

But whenever we find ourselves copying and pasting code (or even just laboriously re-typing it) that’s a little signal we’re potentially creating future pain for ourselves.

Anytime we’re coding there’s an opportunity to introduce an error. Less coding = less errors.

Even if we get it exactly right on the first try (I didn’t just now when I copied sumArray to make multiplyArray), that’s still more code to maintain in the future. Pain.

So the first step is to ask how we can generalize our sumArray and multiplyArray functions into one function that goes through every element in an array and does something with it.

So we’ll reboot the code a bit. I’ll make a looping function (pressArray, you know, like cold-pressed oil), and then some functions that add and multiply:

JS Bin on jsbin.com

Uh oh – check the output! The product has gone from 768 to 0!

So we’ve got a general function that loops through an array, and calls whatever function we give it.

That works fine for adding. But multiplication isn’t working because the number we start with is 0. We end up calculating 0 * 8 * 4 * 4 * 3 * 2. Which is 0.

So we need to be able to say what our beginning value is. In this case we want 1, like in the original version of multiplyArray.

Since our code can’t guess what we’re doing to the array, we’ll have to pass the initial value in:

JS Bin on jsbin.com

What we’ve created is a very simple version of Array.reduce.

Besides input validation, the big difference is that we haven’t added our pressArray function to Array’s prototype. This is currently furiously frowned upon, but if you want to see what it would look like, here it is, renamed press:

JS Bin on jsbin.com

So we’ve reproduced Array.reduce, which takes an array and calculates a single value from that array. Here’s reduce doing the same thing:

JS Bin on jsbin.com

But what if we want to change every element in an array? We need something that will return a new array with updated elements.

That’s what Array.map is for.

Making a simple Array.map

Array.map works very similarly to Array.reduce: It loops through every element of an array, and returns a new array. The new array is based on the old array, but with the elements modified.

Let’s take an example. Say we’re given an array of student test scores, and we need to turn the scores into percentages:

JS Bin on jsbin.com

Now that we know how this works, we can do the same thing we did earlier, and turn our for loop into a generalized function for converting elements in an array. I’ll call the new function ‘convert’:

JS Bin on jsbin.com

Of course, our convert function works just like Array.map, which we can see in action here:

JS Bin on jsbin.com

(Yep, I skipped the bit where we added convert() to Array.prototype.)

So far we’ve covered:

  • Reducing all elements in an array to a single value
  • Using an array to create a new array by mapping the input array’s elements to a new value.

But what if we only want a subset of an array? That’s where filter comes in.

Filtering an array

Let’s stick with the student scores for now. We’ve kept our copy of student score percentages, and want to get all the scores that are more than 50%.

This is the kind of thing Array.filter is used for. Once again, we can make our own version with a simple for loop:

JS Bin on jsbin.com

So you can see this is similar to map: we return an array based on the input array. But this time we don’t transform the elements, we just pick and choose based on a criteria. In this case, is the score greater than or equal to 50%?

It can be generalized an a similar way to our map implementation:

JS Bin on jsbin.com

And we get exactly the same result by using the Array.filter function instead:

JS Bin on jsbin.com

Of course, while these functions save us from repeatedly typing out for loops, they have more to offer than that.

They really come into their own when they’re combined.

Notice in our most recent piece of code, that we save the output of map (the  percentage values), which is an array, and then call filter on it.

It isn’t necessary to do this if we don’t need to save the percentage array. Instead, we can just chain the calls to the array functions like this:

JS Bin on jsbin.com

Which is a way of performing a non-trivial query against our test score data with surprizingly little code.

Not hard, yet not obvious

So we can see that while there’s nothing complicated about JavaScript’s map, reduce and filter array functions, they do hide some details from us.

I think it’s important for anyone just starting out programming to understand those details.

But in the final analysis, map, filter and reduce are way of outsourcing loops to the JavaScript runtime, and let us write simple, elegant code.

Notes

1. I’m not a fan of the word “obvious”! (e.g. “Well, obviously…“) But I’m always happy to talk about making anything ‘more obvious’ 🙂
2. We’re assuming a lot about the parameters here, and would normally see a lot more typechecks. See here for a well checked implementation.

By


Leave a Reply

Your email address will not be published. Required fields are marked *