In order to better understand mapcat I took an example:
user> (mapcat #(list % %) [1 2 3])
(1 1 2 2 3 3)
And tried to reproduce what the doc describes using, on purpose, map and concat :
user> (doc mapcat)
clojure.core/mapcat
([f & colls])
Returns the result of applying concat to the result of applying map
to f and colls. Thus function f should return a collection.
By doing this:
user> (concat (map #(list % %) [1 2 3]))
((1 1) (2 2) (3 3))
However as you can see it doesn't work. I can however use reduce like this but don't know if it's correct:
user> (reduce #(concat %1 %2) (map #(vec (list % %)) [1 2 3]))
(1 1 2 2 3 3)
The above works but I don't know if it's a correct way to recreate, using map and concat, what mapcat does.
Basically I'd like to understand of mapcat works under the hood.
What is going on and how can I access the source of mapcat? (I'm using Emacs + nrepl)
user=> (source mapcat)
(defn mapcat
"Returns the result of applying concat to the result of applying map
to f and colls. Thus function f should return a collection."
{:added "1.0"}
[f & colls]
(apply concat (apply map f colls)))
nil
user=>
The reason reduce
also works is because it is effectively:
(concat (concat '(1 1) '(2 2)) '(3 3))
apply
, as used in the source code, expands to:
(concat '(1 1) '(2 2) '(3 3))
In your initial attempt with concat
:
user=> (map #(list % %) [1 2 3])
((1 1) (2 2) (3 3))
user=> (concat (list '(1 1) '(2 2) '(3 3)))
((1 1) (2 2) (3 3))
user=> (concat [1])
(1)
You can see that if you call concat
with a single argument, it returns that argument.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With