Bobbi Towers / Jun 26 2019

Reduce

(reduce f coll) (reduce f val coll)
Clojure

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.

(reduce + [1 2 3 4 5])
(reduce + [])
(reduce + [1])
(reduce + [1 2])
(reduce + 1 [])
(reduce + 1 [2 3])
6

Converting a vector to a set:

(reduce conj #{} [:a :b :c])
Set(3) #{:c, :b, :a}

Calculate primes until 1000

(reduce
  (fn [primes number]
    (if (some zero? (map (partial mod number) primes))
      primes
      (conj primes number)))
  [2]
  (take 1000 (iterate inc 3)))
Vector(168) [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 148 more...]

Add one collection to another (combining sequences is done with cons):

(reduce conj [1 2 3] [4 5 6])
Vector(6) [1, 2, 3, 4, 5, 6]
(reduce #(cons %2 %1) [1 2 3] [4 5 6])
List(6) (6, 5, 4, 1, 2, 3)

Combine a vector of collections into a single collection of the type of the first collection in the vector.

(reduce into [[1 2 3] [:a :b :c] '([4 5] 6)])
Vector(8) [1, 2, 3, :a, :b, :c, Vector(2), 6]

The flatten function can be used to completely fuse all of the items of a nested tree into a single sequence. Sometimes all that is needed is to fuse the first level of a tree. This can be done with reduce and into.

(reduce into [] '([] [[10 18]] [[8 18]] [[10 12]] [[0 -6]] [[2 6]]))
Vector(5) [Vector(2), Vector(2), Vector(2), Vector(2), Vector(2)]

Some functions update a collection with a single item. A number of functions have a 'more' argument which lets them work over collections. These functions can benefit 'reduce' which lets them work a collection of items...

(into {} {:dog :food})
Map {:dog: :food}
(reduce into {} [{:dog :food} {:cat :chow}])
Map {:dog: :food, :cat: :chow}

The reduction will terminate early if an intermediate result uses the reduced function.

(defn limit [x y] 
  (let [sum (+ x y)] 
    (if (> sum 10) (reduced sum) sum)))

(reduce + 0 (range 10))
(reduce limit 0 (range 10))
15

This will generate the first 100 Fibonacci numbers:

(reduce 
  (fn [a b] (conj a (+' (last a) (last (butlast a)))))  
  [0 1]                      
  (range 98))

Reduce can be used to reimplement a map function:

(defn map* [f & c]
  (let [c* (partition (count c)
                           (apply interleave c))]
    (reduce (fn [s k] (conj s (apply f k))) [] c*)))

(map* * [0.5 0.5 0.5] (range))
(map* str "clojure" (range))
Vector(7) ["c0", "l1", "o2", "j3", "u4", "r5", "e6"]

Update map entries:

(defn update-map-entries [m e]
     (reduce #(update-in %1 [(first %2)] (fn [_] (last %2))) m e))

(update-map-entries {:a 1 :b 2 :c 3} {:a 5 :b 9})
(update-map-entries {:a 1 :b 2 :c 3} {:a 5 :b 9 :d 8})
Map {:a: 5, :b: 9, :c: 3, :d: 8}

Flatten values in a map.

(require '[clojure.set :as set])

(reduce
  (fn [flattened [k v]]
    (set/union flattened v))
  #{}
  {:e #{:m :f}, :c #{:f}, :b #{:c :f}, :d #{:m :f}, :a #{:c :f}})
Set(3) #{:m, :c, :f}

A simple factorial function using reduce:

(defn fact
  [x] 
  (reduce * (range 1 (inc x))))
user/fact

Reduce over maps by destructuring keys:

(def x {:a 1 :b 2})

(reduce (fn [p [k v]]
          (into p {k (+ 1 v)}))
        {} ; First value for p
        x)
Map {:a: 2, :b: 3}

A practical example of mapping over values in a hash-map with the upper-case function:

(reduce
 (fn [acc [k v]]
   (assoc acc k (clojure.string/upper-case v)))
 {}
 {:a "aaaaaaa" :b "bbbbbbb"})
Map {:a: "AAAAAAA", :b: "BBBBBBB"}