Going Functional: Map

Let’s face it: the ‘map’ function (a.k.a. ‘apply-to-all’) is pretty simple. You just pass it an array and a function and it returns an array of results of that function applied to each item.

What’s it all about then? Here comes the important bit: the new array will have the same size as the original one. Always. In other words, the map function defines an ‘N -> N’ mapping. If you see it used, you immediately know the author wants a homomorphism.

Let’s see an example, removing trailing whitespace from strings in a list:

cleanStrings = _.map dirtyStrings, (str) -> str.trim()  

Simple enough, right? Still, there are two things about ‘map’ I’d like to point out.

‘map’ vs ‘each’

Occasionally, you might see code like this:

_.map list, (obj) -> obj.doStuffWithSideEffectsAndNoReturnValue()  

http://www.deshow.net/d/file/animal/2009-07/cute-kitten-631-2.jpg

Adorable kitten 

In this case, map is used for the side effect only. This is no good. Seriously. You’re killing an adorable kitten (see above) when you use map like this. Don’t do it. Also, you’re depriving yourself (and anyone who’s ever going to read your code) of one of the biggest advantages of the functional style: clear expression of intent.

If you see a ‘map’ you should immediately know the programmer wants to transform an array into another array of the same size. If you need to call a function for each item in a list just to trigger its side effect, use ‘each’ instead (just remember to be careful with side effects).

map vs list comprehensions

If you’re lucky enough to write in a language that sports list comprehensions, you can use those to achieve the same result as map.

cleanStrings = (str.trim() for str in dirtyStrings)  

This is pretty neat too. However, there’s a caveat. Comprehensions are more powerful than that, in that they also allow you to filter out some of the items.

Example:

cleanStrings = (s.trim() for s in dirtyStrings when s.length >2)  

So when to use comprehensions and when map?

Well, that is a tough one. When I code in Python I use comprehensions all the time (mainly because of the way anonymous functions are defined in Python, which makes map kind of awkward to use). JavaScript doesn’t have them at all, so ‘map’ it is. In CoffeeScript, which has both, I tend to favor map if I’m doing a N -> N transformation and comprehensions when I need to filter some items out. But as always, use what feels natural to you.

Next in the series comes one of my favorite higher-order functions: reduce. Stay tuned.

Tomas Brambora

Tomas Brambora