Sunday, January 11, 2015

The city of Mapcat

"I have forgot the map."
-- Shakespeare, Henry IV Part I
Act III, Scene I, Line 5.1

Mapcat is an interesting higher order function which is not talked about much.

"You've never danced like this before
We don't talk about it"
-- Milky Chance,
Stolen Dance

The simplest case of Mapcat is when you have a collection of collection and you want to map over the collection of collection yielding a single level of collection.


In the image above we see that we have a collection of two collections (top and bottom) and a function which maps and cats (mapper catter) when these are Mapcatted that yield a result which is a single collection.  The size of the result from the Mapcat is the size of the collection's collections, in the image above we see that we have 4 members of the first collection and 2 members in the second collection giving us the resulting collection with 6 members.

The simplest example of Mapcat would be using the identity function (a function which just returns whatever is given to it).


We see that collection which contains a collection we 1, 2, 3, and 4 and another collection with 20 and 10 when Mapcatted with the Identity function will yield a resulting collection with 1, 2, 3, 4, 20, and 10.

(mapcat identity [[1 2 3 4] [20 10]])
;;(1 2 3 4 20 10)
view raw repl.clj hosted with ❤ by GitHub
new[] {
new[] {1, 2, 3, 4},
new[] {20, 10}
}.SelectMany(x => x);
// { 1, 2, 3, 4, 20, 10 }
view raw repl.cs hosted with ❤ by GitHub


We see in C# we can use the SelectMany to perform this simple Mapcat, while Clojure has a function called mapcat.

This is nice but how about a simple example which actual does something?


How about incrementing the values?

(mapcat #(map inc %) [[1 2 3 4] [20 10]])
;; (2 3 4 5 21 11)
(map inc
(mapcat identity [[1 2 3 4] [20 10]]))
;;(2 3 4 5 21 11)
(->>
[[1 2 3 4] [20 10]]
(mapcat identity)
(map inc))
;;(2 3 4 5 21 11)
view raw repl.clj hosted with ❤ by GitHub
new[] {
new[] {1, 2, 3, 4},
new[] {20, 10}
}.SelectMany(x => x.Select(a => a + 1));
// { 2, 3, 4, 5, 21, 11 }
csharp> new[] {
new[] {1, 2, 3, 4},
new[] {20, 10}
}.SelectMany(x => x).Select(x => x + 1);
//{ 2, 3, 4, 5, 21, 11 }
view raw repl.cs hosted with ❤ by GitHub


We see that in both C# and Clojure the lambda in the Mapcat is given a collection, so in both cases we need to have a function which can work with a collection.  We have a choice in both C# and Clojure we can either have a Map in the lambda or we can chain the result by removing a level with the identity function follow by a simple Map with an incrementing lambda function.  In Clojure we can do chaining using the double arrow macro (thread last) ->> or just nest the calls.