Read my book

I wrote books about Webpack and React. Check them out!

Tuesday, May 10, 2011

Functional Tools - Map, Filter and Reduce

In this post I'm going to introduce three highly useful concepts borrowed straight from functional programming. These concepts, namely map, filter and reduce, allow you to transform given input in a variety of ways. In addition I'll show you how to wrap these three in a nice, chaining environment to make it cooler to use them.

Background


I came by these three little functions during my Python years. They are highly useful beyond Python of course. Here's an example for Rubyists.

Map


Map allows you to transform each item of the given sequence using the given function. Here's one way to implement this:


In addition to the current value I pass item index to the callback. This seems like a nice thing to do. You might want to use the index value for mapping in some cases.

I set up a demo that allows you to play around with the implementation.

Note that JavaScript arrays implement map since version 1.6. MDC.

Filter


Filter allows you to remove items from the given sequence using the given function. You simply check each item against the given rule and decide based on that whether or not to retain it in the result sequence. Here's my implementation:


The demo should illustrate the idea better.

JavaScript arrays implement filter since version 1.6. MDC.

Reduce


Reduce allows you to join the items of the given sequence using the given function. This is done by folding. In this case I'll stick with "left fold". Here's the implementation:


There's a demo available as usual.

JavaScript arrays implement reduce since version 1.8. MDC. There's also "reduceRight" to handle the other case.

Chaining


Since it's kind of boring to write something like filter(map(seq, cb1), cb2) and that's not too readable either, I'll show you how to wrap these little puppies in a chaining wrapper. After this we should end up with a syntax such as this: _(seq).map(cb1).filter(cb2).val(). The extra val() at the end is used to terminate the chain. It will simply return the value of our operations. Here's my implementation:



There's also a demo. Note that in order to make the demo more readable I defined functions that return functions. This technique is also known as currying. It's also possible to define your own lambda syntax though that takes some extra effort.

Conclusion


I hope you found this post useful. I'm not an absolute guru when it comes to functional programming. I do believe, however, that it is valuable to be aware at least some of the concepts related.

This was just the tip of an iceberg. Check out underscore.js for more functional goodies. It's implementation uses various little tricks some of which have been covered here. That's well worth reading to improve your JS-fu. Some nifty stuff there.

Edit: Updated code as per psayre23's suggestions. Much appreciated!