(apply map vector v) transposes a vector in Clojure.
Say I’ve got a vector of vectors.
[[1 2 3] [4 5 6]]
And I want its transpose. Transposing the previous example looks like this:
[[1 4] [2 5] [3 6]]
One way to do that in Clojure is with the following incantation:
(apply map vector [[1 2 3] [4 5 6]])
([1 4] [2 5] [3 6])
I’ve always been delighted by that little fragment of code. If I had to come up with an explanation, perhaps it’s the terse but expressive combination of Clojure’s functional-programming primitives.
I’m going to break down the code snippet, though I fear that, like explaining why a joke is funny, a little of the magic will be lost in translation.
At the core of the thing is a call to good ol’
map takes the form
(map f coll),
where you get a collection of calling
f on every element in
A simple example:
(map inc [1 2 3])
(2 3 4)
One interesting thing about Clojure’s
(and maybe other Lisps as well?)
is that if you pass multiple collections,
successive elements of each will be passed into
(map (fn [a b] (* a b)) [4 5 6] [7 8 9])1
(28 40 54)
The other major piece in the snippet is
a function that takes a function and a collection, and calls the function with collection as arguments.
(apply (fn [a b c] (+ a b c)) [1 2 3])2
(28 40 54)
Putting It Together
Let’s look at the whole thing again:
(apply map vector v).
[[1 2 3] [4 5 6]].
If we break down what
apply is doing here,
it’s equivalent to this:
(map vector [1 2 3] [4 5 6]).
we’ve wound up with the multiple-argument version of
There’s not much more to the story.
vector is a function that takes any number of arguments,
and returns a vector containing those arguments.
(vector 1 2 3) yields
[1 2 3].
(map vector a b) takes the first element from
a and the first element from
then returns a new two-element vector of the two.
Then it proceeds to the second elements of
and so on.
We wind up with the transpose of the original vector.
(I would be remiss if I didn’t note that this formulation actually returns a lazy sequence of the transpose;
if I really need the transpose to be a vector,
I can use
Again, I don’t know precisely what it is that tickles my fancy about this little piece of code. But it’s really cool to see how atomic ideas can plug together into larger molecules of functionality.
Questions? Comments? Contact me!
- Clojure CLI