{:check ["true"], :ranks ["for" "for_advanced"]}

Index

For loops in Clojure

For

In [18]:
(require '[clojure.pprint :refer [pprint]])
Out[18]:
nil

Iteration with (for ...)

In [2]:
;
; (for ...) evaluates to a sequence
;

(for [i (range 10)]
    (str "i=" i))
Out[2]:
("i=0" "i=1" "i=2" "i=3" "i=4" "i=5" "i=6" "i=7" "i=8" "i=9")
In [6]:
(def students [{:name "Jack" :grade 90 :course "Math"}
               {:name "Jill" :grade 88 :course "English"}
               {:name "Joe" :grade 79 :course "English"}])
Out[6]:
#'user/students
In [7]:
;
; (for [<var> <seq>]
;     ...)
; - creates a new scope with the additional symbol binding for <var>.
; - each element in seq is processed exactly once

(for [x students]
    (get x :name))
Out[7]:
("Jack" "Jill" "Joe")
In [16]:
(for [x students]
    (format "%s received %d%% for %s" (:name x)  (:grade x) (:course x)))
Out[16]:
("Jack received 90% for Math" "Jill received 88% for English" "Joe received 79% for English")
In [19]:
;
; (for ...) is a data expression, so it can be used anywhere where
; a sequence is expected.
; 

(pprint (for [x students]
            (format "%s -> %d" (:name x) (:grade x))))
("Jack -> 90" "Jill -> 88" "Joe -> 79")
Out[19]:
nil
In [23]:
(println (clojure.string/join "\n" (for [x students]
                                       (format "%s -> %d" (:name x) (:grade x)))))
Jack -> 90
Jill -> 88
Joe -> 79
Out[23]:
nil
In [7]:
;
; We can iterate through a hash-map as sequence of [key/value] pairs.
;
(def people {"Albert Einstein" {:profession "Physicist"
                                 :date-of-birth {:month "March"
                                                 :day 17
                                                 :year 1879}}
              "Elvis Presley" {:profession "Musician"
                               :date-of-birth {:month "January"
                                               :day 8
                                               :year 1935}}
              "Martin Luther King Jr" {:profession "Minister",
                                       :date-of-birth {:month "January"
                                                       :day 15
                                                       :year 1929}}})
Out[7]:
#'user/people
In [25]:
(count courses)
Out[25]:
3
In [27]:
(for [[name info] courses]
    (format "%s worked as a %s" name (:profession info)))
Out[27]:
("Albert Einstein worked as a Physicist" "Elvis Presley worked as a Musician" "Martin Luther King Jr worked as a Activist")
In [2]:
;
; Idiomatic Clojure -- use functions
;
(defn pad-value [x width]
    (let [string (str x)
          padding (- width (count string))]
        (str x (clojure.string/join "" (repeat padding " ")))))
Out[2]:
#'user/pad-value
In [5]:
(pad-value 3.1415 10)
Out[5]:
"3.1415    "
In [14]:
(defn format-info [name info]
    (let [prof (:profession info)
          month (get-in info [:date-of-birth :month])
          year (get-in info [:date-of-birth :year])]
        (str "| "
             (pad-value name 30)
             "| "
             (pad-value prof 20)
             "| "
             (pad-value (format "%d/%s" year month) 20)
             "|")))
Out[14]:
#'user/format-info
In [15]:
(format-info "Albert Einstein" (get people "Albert Einstein"))
Out[15]:
"| Albert Einstein               | Physicist           | 1879/March          |"
In [16]:
(println
 (clojure.string/join 
  "\n"
  (for [[name info] people]
     (format-info name info))))
| Albert Einstein               | Physicist           | 1879/March          |
| Elvis Presley                 | Musician            | 1935/January        |
| Martin Luther King Jr         | Minister            | 1929/January        |
Out[16]:
nil
In [ ]:

For Advanced

Advanced For Loops in Clojure

In [5]:
;
; for supports iteration over
; multiple sequences using
; variable bindings
;
(for [x (range 5)
      y (range x)]
    [x y])
Out[5]:
([1 0] [2 0] [2 1] [3 0] [3 1] [3 2] [4 0] [4 1] [4 2] [4 3])
In [6]:
;
; (for ...) allows filtering
;
(for [x (range 5)
      y (range x)
      :when (odd? (+ x y))]
    [x y])
Out[6]:
([1 0] [2 1] [3 0] [3 2] [4 1] [4 3])

For loops are lazy

In [15]:
;; about 3 seconds
(time (apply + (for [i (range 1e8)] (Math/pow i 2))))
"Elapsed time: 3195.713617 msecs"
Out[15]:
3.333333283334632E23
In [18]:
(time (def lots-of-squares (for [i (range 1e8)] (Math/pow i 2))))
"Elapsed time: 0.267516 msecs"
Out[18]:
#'user/lots-of-squares
In [19]:
(take 10 lots-of-squares)
Out[19]:
(0.0 1.0 4.0 9.0 16.0 25.0 36.0 49.0 64.0 81.0)
In [ ]: