Functional Programming with Arrays

Oh man do I find this particular style of programming confusing. For one, I’m just more familiar with and comfortable with object-oriented programming. Starting out with Python has left me a bit spoiled! And what’s so bad about for loops anyway?

Okay, well, I’m beginning to learn just how powerful (and cool) functional programming can be. In this particular post, I’ll talk about three functional methods available on Array.prototype: map, filter and reduce.

Array.prototype.map

To me, this is like the gateway functional programming method. It isn’t too complicated. You call map on an array, and it just does something to everthing in the array, and saves it in a new array. It’s like making a photocopy, only you added a little something — like sticky notes? I don’t know, the metaphor is breaking down.

I’m going to give you an example that involves cats, because I like cats, so there.

Let’s start with an array of cat objects:

var cats = [ { name:'Lil Bub', famous: true }, { name: 'Artemis', famous: false }, { name: 'Maru', famous: true }, { name: 'Hubble', famous: false }, { name: 'Grumpy Cat', famous: true }, { name: 'Garfield', famous: true } ];

(Yes, two of those are my cats, of course.)

Let’s say we want to add a default favorite food to each cat after the fact. We might be inclined to write do something like this:

var newCatsArray = []; var newCat; 
for (var i in cats) { newCat = { name: cats[i].name, famous: cats[i].famous, favoriteFood: cats[i].name === 'Garfield' ? 'lasagna' : 'fish' } newCatsArray.push(newCat) }

Cool. After going through all those iterations, we do end up with a new cat array that does contain a favorite food (fish by default, lasagna if it’s Garfield). There’s nothing really.. wrong with this code. It’s just a bit long, and there’s some stuff in there that you have to remember (for example, using cats[i] to represent the current cat). It just takes you a moment to know what’s happening, and it looks a bit messy. I think we can do better!

Let’s try this using map:

var newCatsArray = cats.map(function(cat, i){ return { name: cat.name, famous: cat.famous, favoriteFood: cat.name === 'Garfield' ? 'lasagna' : 'fish' } });

And that’s it! Now newCatsArray is a new array containing cats, their fame status, and their favoriteFood. It’s pretty clear what’s happening — we’re creating a copy of the array with something new. And we’re able have the entire modification happen in nice, simple line of code — we’re just returning the new object.

Array.prototype.filter

Next up is filter. I think this method is a fairly easy one to understand once you get the hang of it. Basically, we’ll call filter on our array, and as an argument, we’ll provide a callback function. Filter will return a new array that only contains the elements of the original array for which the function returned true.

Back to our cats:

var cats = [ { name:'Lil Bub', famous: true }, { name: 'Artemis', famous: false }, { name: 'Maru', famous: true }, { name: 'Hubble', famous: false }, { name: 'Grumpy Cat', famous: true }, { name: 'Garfield', famous: true } ];

Okay, so I love my cats. But maybe you’re like “I don’t care about your dumb, non-famous cats! Give me a list of just the famous ones!”

Fine, fine, I understand. Let’s get a new array of cats that only includes famous ones:

var famousCats = []; for (var i in cats) { if (cats[i].famous) { famousCats.push(cats[i]); }
}

Hmm, that’s okay, but given what we learned in the last section, I’m sure you can see that there might be a nicer way to do this. Let’s see what we can do with filter:

var famousCats = cats.filter(function(cat) { return cat.famous; });

That’s literally it. How cool is that? Way more readable than the for loop above (even if I do love me a good for loop, I have to admit this essentially one-line piece of code is a lot more elegant!)

Array.prototype.reduce

Okay, so filter and map may take a moment to get used to, but they’re pretty straightforward. Things get pretty weird when you start using reduce, but bear with me.

The reduce method is going to take a callback function, too. Instead of going through each item in the array, however, it’s going to do something a little different. On each iteration, it will have a previousItem and currentItem argument. Basically, you’re going to be processing 2 items at a time until your array is down to 1 item. And then, you get that one item returned.

A bit confusing, but let’s try an example.

Say we’re back to our famous and non-famous cats array:

var cats = [ { name:'Lil Bub', famous: true }, { name: 'Artemis', famous: false }, { name: 'Maru', famous: true }, { name: 'Hubble', famous: false }, { name: 'Grumpy Cat', famous: true }, { name: 'Garfield', famous: true } ];

In the last exercise, you didn’t want to see my cats in the list (mean!). But now, you actually just want to know what are the names of my cats. That’s it. But you want a string, not an array.

Hmm, this poses a problem. Our other methods return arrays.

Without we might start with a simple iterative approach, after filtering out the famous cats:

var str = "Allie's cat's are named: "; var myCats = []; for (var i in cats) { if (!cats[i].famous) { myCats.push(cats[i].name) }; } str += myCats.join(" & ");

But using filter and reduce together, we can take your array and reduce it down to a single element with no trouble. Check it out:

var str = "Allie's cats are named: "; str += cats.filter(function(cat) { return !cat.famous; }).reduce(function(previousCat, currentCat) { return previousCat.name + " & " + currentCat.name + "."; });

Console logging str, we would see: “Allie’s cats are named: Artemis & Hubble.”

That’s all for now on this topic. See any errors or have any suggestions? Feel free to comment below, or send me an email.


Originally published at paloobi.tumblr.com.

Show your support

Clapping shows how much you appreciated Alexandra Polubiec’s story.