ClojureDocs

导航

命名空间

for

clojure.core

自 1.0 起已推出 (资源)
  • (for seq-exprs body-expr)
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]))
18 Examples
;; 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)
(def digits [1 2 3])

(for [x1 digits
      x2 digits]
  (* x1 x2))
;;=> (1 2 3 2 4 6 3 6 9)
;; 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])
;; produce a seq of squares
(for [x (range 6)] 
  (* x x))
;;=> (0 1 4 9 16 25)
;; 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))
See Also

Repeatedly executes body (presumably for side-effects) with bindings and filtering as provided by ...

Added by mmwaikar

When lazy sequences are produced via functions that have side effects, any effects other than thos...

Added by Dimagog

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...

Added by bheesham

binding => binding-form init-expr binding-form => name, or destructuring-form destructuring-form...

Added by MicahElliott

Evaluates test. If logical true, evaluates body in an implicit do.

Added by MicahElliott
6 Notes
    By , created 14.7 years ago

    My English parser was choking on the description of this function.

    This SO question has helped clarify how this function works.

    By , created 14.7 years ago

    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]))
    
    By , created 13.6 years ago, updated 13.6 years ago

    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=>
    
    By , created 12.3 years ago, updated 12.3 years ago

    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.

    By , created 11.7 years ago

    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))

    By , created 11.1 years ago

    "Sequence comprehension", not "list comprehension".