In page 120 of "Clojure Programming".
(reduce-by :customer #(+ %1 (:total %2)) 0 orders) =>
key-fn: :customer
f: #(+ %1 (:total %2))
init: 0
coll: orders
user=> (doc reduce)
clojure.core/reduce ([f coll] [f val coll]) f should be a function of 2 arguments. If val is not supplied, returns the result of applying f to the first 2 items in coll, then applying f to that result and the 3rd item, etc. If coll contains no items, f must accept no arguments as well, and reduce returns the result of calling f with no arguments. If coll has only 1 item, it is returned and f is not called. If val is supplied, returns the result of applying f to val and the first item in coll, then applying f to that result and the 2nd item, etc. If coll contains no items, returns val and f is not called.
According to above definition, summaries is the second argument of reduce ({}), x is the first element of coll (orders).
user=> (doc assoc)
clojure.core/assoc ([map key val] [map key val & kvs]) assoc[iate]. When applied to a map, returns a new map of the same (hashed/sorted) type, that contains the mapping of key(s) to val(s). When applied to a vector, returns a new vector that contains val at index. Note - index must be <= (count vector).
The run the following script in repl:
(def orders
[{:product "Clock", :customer "Wile Coyote", :qty 6, :total 300}
{:product "Dynamite", :customer "Wile Coyote", :qty 20, :total 5000}
{:product "Shotgun", :customer "Elmer Fudd", :qty 2, :total 800}
{:product "Shells", :customer "Elmer Fudd", :qty 4, :total 100}
{:product "Hole", :customer "Wile Coyote", :qty 1, :total 1000}
{:product "Anvil", :customer "Elmer Fudd", :qty 2, :total 300}
{:product "Anvil", :customer "Wile Coyote", :qty 6, :total 900}])
(defn reduce-by
[key-fn f init coll]
(println "key-fn:" key-fn)
(println "f:" f)
(println "init:" init)
(println "coll:" coll)
(println "==========")
(reduce (fn [summaries x]
(let [k (key-fn x)]
(println "summaries:" summaries)
(println "k:" k)
(println "x:" x)
(println "(key-fn x):" (key-fn x))
(println "value for k:" (f (summaries k init) x))
(println "---------")
(assoc summaries k (f (summaries k init) x))))
{} coll))
(reduce-by :customer #(+ %1 (:total %2)) 0 orders)
And the output:
key-fn: :customer
f: #
init: 0
coll: [{:total 300, :customer Wile Coyote, :qty 6, :product Clock} {:total 5000, :customer Wile Coyote, :qty 20, :product Dynamite} {:total 800, :customer Elmer Fudd, :qty 2, :product Shotgun} {:total 100, :customer Elmer Fudd, :qty 4, :product Shells} {:total 1000, :customer Wile Coyote, :qty 1, :product Hole} {:total 300, :customer Elmer Fudd, :qty 2, :product Anvil} {:total 900, :customer Wile Coyote, :qty 6, :product Anvil}]
==========
summaries: {}
k: Wile Coyote
x: {:total 300, :customer Wile Coyote, :qty 6, :product Clock}
(key-fn x): Wile Coyote
value for k: 300
summaries: {Wile Coyote 300}
k: Wile Coyote
x: {:total 5000, :customer Wile Coyote, :qty 20, :product Dynamite}
(key-fn x): Wile Coyote
value for k: 5300
summaries: {Wile Coyote 5300}
k: Elmer Fudd
x: {:total 800, :customer Elmer Fudd, :qty 2, :product Shotgun}
(key-fn x): Elmer Fudd
value for k: 800
summaries: {Elmer Fudd 800, Wile Coyote 5300}
k: Elmer Fudd
x: {:total 100, :customer Elmer Fudd, :qty 4, :product Shells}
(key-fn x): Elmer Fudd
value for k: 900
summaries: {Elmer Fudd 900, Wile Coyote 5300}
k: Wile Coyote
x: {:total 1000, :customer Wile Coyote, :qty 1, :product Hole}
(key-fn x): Wile Coyote
value for k: 6300
summaries: {Elmer Fudd 900, Wile Coyote 6300}
k: Elmer Fudd
x: {:total 300, :customer Elmer Fudd, :qty 2, :product Anvil}
(key-fn x): Elmer Fudd
value for k: 1200
summaries: {Elmer Fudd 1200, Wile Coyote 6300}
k: Wile Coyote
x: {:total 900, :customer Wile Coyote, :qty 6, :product Anvil}
(key-fn x): Wile Coyote
value for k: 7200
Verified on Eclipse Juno SR2 with Counterclockwise plugin, Mint 14 Xfce, 2013-10-6.