ClojureDocs

Nav

Namespaces

mapcat

clojure.core

Available since 1.0 (source)
  • (mapcat f)
  • (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. Returns
a transducer when no collections are provided
9 Examples
user=> (mapcat reverse [[3 2 1 0] [6 5 4] [9 8 7]])
(0 1 2 3 4 5 6 7 8 9)
user=> (mapcat (fn [[k v]] 
                 (for [[k2 v2] v] 
                   (concat [k k2] v2)))
         '{:a {:x (1 2) :y (3 4)}
           :b {:x (1 2) :z (5 6)}})

((:a :x 1 2) (:a :y 3 4) (:b :x 1 2) (:b :z 5 6))
user=> (require '[clojure.string :as cs])
nil

;; Suppose you have a fn in a `map` that itself returns
;; multiple values.
user=> (map #(cs/split % #"\d") ["aa1bb" "cc2dd" "ee3ff"])
(["aa" "bb"] ["cc" "dd"] ["ee" "ff"])

;; Now, if you want to concat them all together, you *could*
;; do this:
user=> (apply concat (map #(cs/split % #"\d") ["aa1bb" "cc2dd" "ee3ff"]))
("aa" "bb" "cc" "dd" "ee" "ff")

;; But `mapcat` can save you a step:
user=> (mapcat #(cs/split % #"\d") ["aa1bb" "cc2dd" "ee3ff"])
("aa" "bb" "cc" "dd" "ee" "ff")
;; Suppose you've got a function that takes a value
;; and returns a list of things from it, for example:
(defn f1
  [n]
  [(- n 1) n (+ n 1)])

(f1 1)
;=> [0 1 2]

;; Perhaps you'd like to map it onto each item in a collection:
(map f1 [1 2 3])
;=> ([0 1 2] [1 2 3] [2 3 4])

;; But suppose you wanted them all concatenated? You could do this:
(apply concat (map f1 [1 2 3]))
;=> (0 1 2 1 2 3 2 3 4)

;; Or you could get the same thing with `mapcat`:
(mapcat f1 [1 2 3])
;=> (0 1 2 1 2 3 2 3 4)
; Flatten a map, consing keys on to each nested vector 
(mapcat (fn [[k vs]] (map (partial cons k) vs)) {:foo [[1 2] [3 2]] :bar [[3 1]]})
;=> ((:foo 1 2) (:foo 3 2) (:bar 3 1))
;; A very useful feature of mapcat is that it allows function f to produce no result
;; by returning nil or an empty collection:
(mapcat #(remove even? %) [[1 2] [2 2] [2 3]])
;; => (1 3)

;; note that applying (remove even?) to [2 2] produced () which was "eaten"
;; and ignored by mapcat.
;; map vs. mapcat -
;; For duplicating each item in a sequence

;; Using map:
(map #(repeat 2 %) [1 2])
;; => ((1 1) (2 2))

;; Using mapcat:
(mapcat #(repeat 2 %) [1 2])
;; => (1 1 2 2)
;; I think it is cool to use juxt together with mapcat
;; mapcat requires element to be collection and the result of juxt will be collection. 

(mapcat (juxt inc dec)  [1 2 3 4])
;; => (2 0 3 1 4 2 5 3)
;;(mapcat f & colls)
(mapcat list [:a :b :c] [1 2 3])
;;=> (:a 1 :b 2 :c 3)
See Also

Returns a lazy sequence consisting of the result of applying f to the set of first items of each c...

Added by gstamp

Returns a lazy seq representing the concatenation of the elements in the supplied colls.

Added by gstamp

Takes any nested combination of sequential things (lists, vectors, etc.) and returns their content...

Added by MicahElliott
1 Note
    By , created 7.1 years ago, updated 7.1 years ago
    ;; mapcat always evaluates the first 4 arguments.
    (def a (mapcat range (map #(do (print ".") %) (into () (range 10)))))
    ;; ....
    
    ;; it can be solved avoiding 'apply' to handle varargs
    (defn mapcat* [f & colls]
      (letfn [(step [colls]
                (lazy-seq
                  (when-first [c colls]
                    (concat c (step (rest colls))))))]
        (step (apply map f colls))))
    
    (def a (mapcat* range (map #(do (print ".") %) (into () (range 10)))))
    ;; nothing prints