List comprehension. Takes a vector of one or more binding-form/collection-expr pairs, each followed by zero or more modifiers, and yields a lazy sequence of evaluations of expr. Collections are iterated in a nested fashion, rightmost fastest, and nested coll-exprs can refer to bindings created in prior binding-forms. Supported modifiers are: :let [binding-form expr ...], :while test, :when test. (take 100 (for [x (range 100000000) y (range 1000000) :while (< y x)] [x y]))
;; prepare a seq of the even values ;; from the first six multiples of three (for [x [0 1 2 3 4 5] :let [y (* x 3)] :when (even? y)] y) ;;=> (0 6 12)
;; produce a seq of all pairs drawn from two vectors (for [x ['a 'b 'c] y [1 2 3]] [x y]) ;;=> ([a 1] [a 2] [a 3] [b 1] [b 2] [b 3] [c 1] [c 2] [c 3])
;; produce a seq of the first three powers for a range of integers (for [x (range 1 6) :let [y (* x x) z (* x x x)]] [x y z]) ;;=> ([1 1 1] [2 4 8] [3 9 27] [4 16 64] [5 25 125])
;; prepare a seq of all keys from entries whose values are 0 (for [[x y] '([:a 1] [:b 2] [:c 0]) :when (= y 0)] x) ;;=> (:c)
;; Demonstrating performance difference between :when and :while (time (dorun (for [x (range 1000) y (range 10000) :when (> x y)] [x y]))) ;; "Elapsed time: 2898.908 msecs" ;;=> nil (time (dorun (for [x (range 1000) y (range 10000) :while (> x y)] [x y]))) ;; "Elapsed time: 293.677 msecs" ;;=> nil
;; Demonstrating functional difference between :when and :while (for [x (range 3) y (range 3)] [x y]) ;;=> ([0 0] [0 1] [0 2] ;; [1 0] [1 1] [1 2] ;; [2 0] [2 1] [2 2]) (for [x (range 3) y (range 3) :when (not= x y)] [x y]) ;;=> ( [0 1] [0 2] ;; [1 0] [1 2] ;; [2 0] [2 1] ) ; Here we see the :while applied to the immediately preceding seq (for [x (range 3) y (range 3) :while (not= x y)] [x y]) ;;=> ( ;; [1 0] ;; [2 0] [2 1] ) ;; The placement of the :while is important ;; :while can cause a halt for a particular sequence (for [x (range 3) y (range 3) :while (not= x 1)] [x y]) ;;=> ([0 0] [0 1] [0 2] [2 0] [2 1] [2 2]) (for [x (range 3) :while (not= x 1) y (range 3)] [x y]) ;;=> ([0 0] [0 1] [0 2])
;; More examples illustrating the difference between :when and :while ;; Simple but inefficient method of checking whether a number is ;; prime. user=> (defn prime? [n] (not-any? zero? (map #(rem n %) (range 2 n)))) #'user/prime? user=> (range 3 33 2) (3 5 7 9 11 13 15 17 19 21 23 25 27 29 31) ;; :when continues through the collection even if some have the ;; condition evaluate to false, like filter user=> (for [x (range 3 33 2) :when (prime? x)] x) (3 5 7 11 13 17 19 23 29 31) ;; :while stops at the first collection element that evaluates to ;; false, like take-while user=> (for [x (range 3 33 2) :while (prime? x)] x) (3 5 7) ;; The examples above can easily be rewritten with filter or ;; take-while. When you have a for with multiple binding forms, so ;; that the iteration occurs in a nested fashion, it becomes possible ;; to write something briefly with 'for' that would be more verbose or ;; unwieldy with nested filter or take-while expressions. user=> (for [x (range 3 17 2) :when (prime? x) y (range 3 17 2) :when (prime? y)] [x y]) ([ 3 3] [ 3 5] [ 3 7] [ 3 11] [ 3 13] [ 5 3] [ 5 5] [ 5 7] [ 5 11] [ 5 13] [ 7 3] [ 7 5] [ 7 7] [ 7 11] [ 7 13] [11 3] [11 5] [11 7] [11 11] [11 13] [13 3] [13 5] [13 7] [13 11] [13 13]) user=> (for [x (range 3 17 2) :while (prime? x) y (range 3 17 2) :while (prime? y)] [x y]) ([3 3] [3 5] [3 7] [5 3] [5 5] [5 7] [7 3] [7 5] [7 7]) ;; This example only gives a finite result because of the :while ;; expressions. user=> (for [x (range) :while (< x 10) y (range) :while (<= y x)] [x y]) ([0 0] [1 0] [1 1] [2 0] [2 1] [2 2] [3 0] [3 1] [3 2] [3 3] [4 0] [4 1] [4 2] [4 3] [4 4] [5 0] [5 1] [5 2] [5 3] [5 4] [5 5] [6 0] [6 1] [6 2] [6 3] [6 4] [6 5] [6 6] [7 0] [7 1] [7 2] [7 3] [7 4] [7 5] [7 6] [7 7] [8 0] [8 1] [8 2] [8 3] [8 4] [8 5] [8 6] [8 7] [8 8] [9 0] [9 1] [9 2] [9 3] [9 4] [9 5] [9 6] [9 7] [9 8] [9 9])
;; Here are a couple of examples where the only difference is where ;; the :while is placed, but it makes a significant difference in the ;; behavior. ;; When x=2 y=1 is reached, :while (<= x y) evaluates false, so all ;; further items in the y collection are skipped. When x=3 y=1 is ;; reached, the same thing happens. user=> (for [x [1 2 3] y [1 2 3] :while (<= x y) z [1 2 3]] [x y z]) ([1 1 1] [1 1 2] [1 1 3] [1 2 1] [1 2 2] [1 2 3] [1 3 1] [1 3 2] [1 3 3]) ;; This is different. When x=2 y=1 z=1 is reached, :while (<= x y) ;; evaluates false, but since the :while is after the binding for z, ;; all further items in the z collection are skipped. Then x=2 y=2 ;; z=1 is tried, where the while expresssion evaluates true. user=> (for [x [1 2 3] y [1 2 3] z [1 2 3] :while (<= x y)] [x y z]) ([1 1 1] [1 1 2] [1 1 3] [1 2 1] [1 2 2] [1 2 3] [1 3 1] [1 3 2] [1 3 3] [2 2 1] [2 2 2] [2 2 3] [2 3 1] [2 3 2] [2 3 3] [3 3 1] [3 3 2] [3 3 3])
(defn all-files-present? "Takes a list of real file names, and returns a map of files present 1 and not present 0." [file-seq] (for [fnam file-seq :let [stat-map {(keyword fnam) (look-for fnam "f")}]] stat-map)) (into {} (all-files-present? '("Makefile" "build.sh" "real-estate.csv"))) {:Makefile 1, :build.sh 1, :real-estate.csv 0}
;; Flattening a seq of pairs using for comprehensions (def pairs (for [i (range 10)] [i (inc i)])) ;; ([0 1] [1 2] [2 3] [3 4] [4 5] [5 6] [6 7] [7 8] [8 9] [9 10]) (def flattened (for [pair pairs element pair] element)) ;; (0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10)
;; Given an array of integers, return indices of the two numbers such that they ;; add up to a specific target. ;; You may assume that each input would have exactly one solution. ;; Given nums = [2, 7, 11, 15], target = 9, ;; Because nums[0] + nums[1] = 2 + 7 = 9, ;; return [0, 1]. (defn two-sum [nums target] (let [nums-index (zipmap nums (range)) indexs (for [[x i] nums-index [y j] nums-index :when (< i j) :when (= (+ x y) target)] [i j])] (first indexs))) (two-sum [2 7 11 15] 9) ;; [0 1]
;;; Cartesian products of two sets (#(set (for[x %1, y %2] [x y])) #{1 2 3} #{4 5}) ;=> #{[2 5] [3 4] [1 4] [1 5] [2 4] [3 5]}
;; Nested 'for' example to produce indexes of Two-dimensional array (for [i (range 3)] (for [j (range 3)] [i j])) ;=> (([0 0] [0 1] [0 2]) ; ([1 0] [1 1] [1 2]) ; ([2 0] [2 1] [2 2]))
;; Generate the hiccup for a collection of books, each book has unique details defined in each hash-map inside the collection. ;; Destructure the keys in the hash-map for each book in turn (def practicalli-book-list [{:title "Practicalli Spacemacs" :url "https://practical.li/spacemacs" :image "/practicalli-spacemacs-book-banner.png" :description "Coding Clojure with Emacs and Vim multi-modal editing"} {:title "Practicalli Clojure" :url "https://practical.li/clojure" :image "/practicalli-clojure-book-banner.png" :description "Learn the Clojure language through REPL driven development"}]) (defn books-list [books] (for [{:keys [title description url image]} books] [:div {:class "column"} [:a {:href url :target "_blank"} [:img {:src image}]] [:p [:a {:href url :target "_blank" } title] description]])) (book-list practicalli-book-list) ;; => [:div {:class "box"} [:div {:class "column"} [:h2 {:class "title has-text-centered"} "Freely available online books"]] nil ([:div {:class "column"} [:div {:class "columns"} [:div {:class "column"} [:a {:href "https://practical.li/spacemacs", :target "_blank"} [:figure {:class "image"} [:img {:src "/practicalli-spacemacs-book-banner.png"}]]]] [:div {:class "column"} [:p [:a {:href "https://practical.li/spacemacs", :target "_blank", :class "has-text-weight-bold"} "Practicalli Spacemacs"] "Emacs and Vim multi-modal editing"]]]] [:div {:class "column"} [:div {:class "columns"} [:div {:class "column"} [:a {:href "https://practical.li/clojure", :target "_blank"} [:figure {:class "image"} [:img {:src "/practicalli-clojure-book-banner.png"}]]]] [:div {:class "column"} [:p [:a {:href "https://practical.li/clojure", :target "_blank", :class "has-text-weight-bold"} "Practicalli Clojure"] "Learn the Clojure language through REPL driven development"]]]])]
;; Easy iteration through nested vectors (def matrix [["a" "b"] ["c" "d"]]) (for [row matrix letter row] letter) ;; ("a" "b" "c" "d")
;; to map across a hashmap (for [[k v] {:a 1 :b 10 :c 100}] (list k v)) ;; -> ((:a 1) (:b 10) (:c 100))
Repeatedly executes body (presumably for side-effects) with bindings and filtering as provided by ...
When lazy sequences are produced via functions that have side effects, any effects other than thos...
Evaluates the exprs in order, then, in parallel, rebinds the bindings of the recursion point to the ...
Returns a lazy seq of nums from start (inclusive) to end (exclusive), by step, where start default...
binding => binding-form init-expr binding-form => name, or destructuring-form destructuring-form...
Evaluates test. If logical true, evaluates body in an implicit do.
My English parser was choking on the description of this function.
This SO question has helped clarify how this function works.
Example 1 can be rewritten without using the for macro. Pure functional should be preferred if possible:
(filter even? (map (partial * 3) [0 1 2 3 4 5]))
On juergenhoetzel's comment:
All the examples could be re-written in some combination of map and filter, but they are still valid examples of using the for comprehension, AFAIK:
Examples:
user=> (mapcat (fn [e] (map (fn [x] (* x e)) [1 2 3])) [1 2 3]) (1 2 3 2 4 6 3 6 9) user=> (mapcat (fn [e] (map (fn [x] [e x]) [1 2 3])) ['a 'b 'c]) ([a 1] [a 2] [a 3] [b 1] [b 2] [b 3] [c 1] [c 2] [c 3]) user=> (map (fn [e] [e (* e e)(* e e e)]) (range 1 6)) ([1 1 1] [2 4 8] [3 9 27] [4 16 64] [5 25 125]) user=> (map (fn [e] (* e e)) (range 3 7)) (9 16 25 36) user=> (map first (filter (fn [[x y]] (= y 0)) '([:a 1] [:b 2] [:c 0]))) (:c) user=>
Take careful note of the description's wording:
binding-form/collection-expr pairs, each followed by zero or more modifiers
A consequence is that the binding list may not begin with a modifier, i.e a :let
, :when
or :while
!
The following example is illegal syntax:
(for [:let [a 1] b (range 5)] {a b})
While it might sometimes be convenient to start a for
with a :let
to reduce code clutter, the "correct" procedure is to nest the for
in a "proper" let
, like this:
(let [a 1] (for [b (range 5)] {a b}))
Similarly, a :when
is better represented by nesting in an if
.
The fifth example should probably be shown in first position, it's the most straightforward and readable for a beginner :
(for [x (range 3 7)] (* x x))