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()
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.
cleanStrings = (s.trim() for s in dirtyStrings when s.length >2)
So when to use comprehensions and when map?
Next in the series comes one of my favorite higher-order functions: reduce. Stay tuned.