Collections

Merge Maps With Function To Set Value Duplicate Keys

In Clojure we can use the merge function to merge multiple maps into a single map. If a key is in multiple maps the value of the key merged last will be used in the resulting map. If we want to influence how the value of a duplicate key is set we can use merge-with. We specify as first argument the function that will be used when the same key is available in multiple maps. The function must accept two arguments, where the the first argument is the value of the key in the first map and the second argument the value of the same key in the following map. The result is assigned to the key in the resulting map. If we pass more than two maps to the merge-with the function will be called multiple times for a key if it is part of more than two maps.

In the following example we use Clojure core functions and a custom function to merge multiples maps, so we can alter the value for duplicate keys:

(ns mrhaki.core.merge-with
  (:require [clojure.test :refer [is]]))

;; Merge maps and use the function specified as first argument
;; to calculate the value for keys that are present
;; in multiple maps.
(is (= {:a 60 :b 3 :c 44 :d 100}
       (merge-with * {:a 2 :b 3 :c 4} {:a 10 :c 11} {:a 3 :d 100})))

;; Works for all maps and independent of type that is used for keys.
;; We can use any function for merge-with.
(def languages (merge-with (comp vec flatten conj) {"Clojure" [:dynamic :functional]}
                           {"Java" [:jvm]}
                           {"Groovy" [:jvm]}
                           {"Clojure" [:jvm]}
                           {"Groovy" [:dynamic]}))

(is (= {"Clojure" [:dynamic :functional :jvm]
        "Java"    [:jvm]
        "Groovy"  [:jvm :dynamic]}
       languages))


;; Sample map with small inventory.
(def inventory {"pencil" {:count 10 :price 0.25}
                "pen"    {:count 23 :price 0.4}})
;; Sample basket with items.
(def basket {"pencil" {:count 5} "pen" {:count 2}})

;; Function to subtract the :count value for a basket item
;; from the :count value for the same inventory item.
(defn item-sold
  [inventory-item basket-item]
  (update-in inventory-item [:count] - (:count basket-item)))

(is (= {"pencil" {:count 5 :price 0.25}
        "pen"    {:count 21 :price 0.4}}
       (merge-with item-sold inventory basket)))

Written with Clojure 1.10.1.

Original post written on February 23, 2021

Split Collection With Predicate

To split a collection in Clojure we can use the split-with and split-at functions. The split-with function takes a predicate as first argument and a colletion as second argument. The function will return a vector with two items. The first item is the result of the function take-while with the given predicate. The second item in the result vector is the resul of the drop-while function with the same predicate.

We use the split-at function with a number as first argument followed by a collection to split based on a given number of items. Instead of using a predicate we can define the number of items that we want as the first item in the result vector. The first item in the result vector is the result of invoking the take function. The resulting number of items of the collection will be the second item in the result vector and is achieved by invoking the drop function.

In the following example we use both functions with different arguments:

(ns mrhaki.core.split
  (:require [clojure.test :refer [is]]))

;; The split-with function has a predicate and returns the result 
;; of the functions take-while and drop-while in a result vector.
(let [less-than-5? (partial > 5)
      numbers      (range 11)]
  (is (= ['(0 1 2 3 4) '(5 6 7 8 9 10)]
         (split-with less-than-5? numbers))
         [(take-while less-than-5? numbers) (drop-while less-than-5? numbers)]))

;; In this example we take while the value is a String value and 
;; drop while starting from first value that is not a String.
(letfn [(string-value? [[k v]] (instance? String v))]
  (is (= ['([:language "Clojure"] [:alias "mrhaki"]) '([:age 47] [:country "NL"])]
         (split-with string-value? {:language "Clojure" :alias "mrhaki" :age 47 :country "NL"}))))


;; Instead of splitting on a predicate we can just give the number
;; of elements we want to split on with the split-at function.
(is (= ['(0 1 2 3) '(4 5 6 7)]
       (split-at 4 (range 8))
       [(take 4 (range 8)) (drop 4 (range 8))]))

(is (= ['([:language "Clojure"] [:alias "mrhaki"] [:age 47]) '([:country "NL"])]
       (split-at 3 {:language "Clojure" :alias "mrhaki" :age 47 :country "NL"})))

Clojure 1.10.1.

Original post written on October 14, 2020

Concatenation Of Map Function Results With mapcat

When we use a function as argument for the map function that returns a collection we would get nested collections. If we want to turn the result into a single collection we can concatenate the elements from the collections by applying the concat function, but we can do this directly with the function mapcat. The function mapcat takes as first argument a function (that returns a collection) and one or more collections as next arguments.

In the following examples we see several uses of mapcat:

(ns mrhaki.core.mapcat
  (:require [clojure.test :refer [is]]))

;; The function argument for mapcat returns a collection
;; with the original element of the collection
;; and the value added by 10.
(is (= [1 11 2 12 3 13]
       (mapcat (fn [n] [n (+ 10 n)]) [1 2 3])))

(is (= [1 1 2 2 3 3]
       (mapcat (partial repeat 2) [1 2 3])
       ;; Using apply concat with map returns the same result.
       (apply concat (map (partial repeat 2) [1 2 3]))))

;; Combined with juxt
(is (= ["mrhaki" 6 "blog" 4]
       (mapcat (juxt identity count) ["mrhaki" "blog"])))

;; Our first example rewritten with juxt.
(is (= [1 11 2 12 3 13]
       (mapcat (juxt identity (partial + 10)) [1 2 3])))

;; We can use multiple collections,
;; the function then accepts multiple arguments.
(is (= [1 100 100 2 200 400 3 300 900]
       (mapcat (fn [a b] [a b (* a b)]) [1 2 3] [100 200 300])))

Written with Clojure 1.10.1.

Original post written on July 5, 2020

Transforming Collection Items With Index

If we want to transform items in a collection we can use the map function. If we also want to use the index of the element in the collection in the transformation we must use the map-indexed function. We must provide a function with 2 arguments, where the first argument is the index of the element in the collection and the second argument is the element in the collection.

In the following examples we use the map-indexed function:

(ns mrhaki.core.map-indexed
  (:require [clojure.test :refer [is]]))

;; map-indexed applies a function to each element
;; in a collection where the function gets the
;; index of the item in the collection and the item itself.
(is (= [[0 3] [1 20] [2 10] [3 2] [4 1]]
       (map-indexed (fn [index number] [index number]) [3 20 10 2 1])))


(defn indices
  "Return lazy sequence of indices of elements in a collection."
  [coll]
  (map-indexed (fn [index _] index) coll))

(is (= [0 1 2 3 4] (indices [3 20 10 2 1])))


(defn char-range
  "Function to return a range of characters from `start` to `end` (including)."
  [start end]
  (map char (range (int start) (inc (int end)))))

(def a-z (char-range \a \z)) ;; characters from a to z.

;; map-indexed returns a lazy sequence.
(is (= [[\a 0] [\b 1] [\c 2]]
       (take 3 (map-indexed (fn [index ch] [ch index]) a-z))))


;; Create map with letter keys and position in alphabet as values.
(def letters-positions (into {} (map-indexed (fn [index ch] [ch (inc index)]) a-z)))

(is (= [[\a 1] [\b 2] [\c 3]]
       (take 3 letters-positions)))

;; Find position of each letter of word "clojure".
(is (= [3 12 15 10 21 18 5]
       (reduce (fn [result value] (conj result (get letters-positions value)))
               []
               "clojure")))

Written with Clojure 1.10.1.

Original post written on June 8, 2020

Repeat Items In A Collection As Lazy Sequence With cycle

The Clojure function cycle take a collections as argument and creates a lazy sequence by repeating the items in the collection. So if we pass a collection with the characters \a, \b and \c we get a lazy sequence of (\a \b \c \a \b \c ...).

(ns mrhaki.core.cycle
  (:require [clojure.test :refer [is]]))

;; The items in the collection are repeated
;; and return type is a lazy sequence.
(is (= [0 1 0 1 0 1] 
       (take 6 (cycle [0 1]))))
(is (seq? (cycle [0 1])))

(is (= [\C \l \o \j \u \r \e \C \l \o \j \u \r \e]
       (take 14 (cycle "Clojure"))))

;; Useful for functions that want equally sized 
;; collection arguments.
(is (= {:a 0 :b 1 :c 0 :d 1} 
       (zipmap [:a :b :c :d] (cycle [0 1]))))

Written with Clojure 1.10.1.

Original post written on June 2, 2020

Interleave Keys And Values Into A Map With zipmap

The Clojure function zipmap create a map by interleaving a collection of keys with a collection of values. The first element of the keys collection is the map entry keyword and the first element of the values collection is than the map entry value, and so on for the other elements in the keys and values collections.

In the following example code we use zipmap using different examples of keys and values collections:

(ns mrhaki.core.zipmap
  (:require [clojure.test :refer [is]]))

;; zipmap creates a map with keys from the
;; first collection and values from the second.
(is (= {:name "Hubert" :alias "mrhaki"} 
       (zipmap [:name :alias] ["Hubert" "mrhaki"])))

;; If the size of the values collection is smaller
;; than the size of the keys collection, only 
;; keys that map to a value end in up
;; in the resulting map. 
(is (= {:name "Hubert"}
       (zipmap [:name :alias] ["Hubert"])))

;; If the size of the keys collection is smaller
;; than the size of the value collection, then the
;; returned map only contains keys from the keys 
;; collection and some values are ignored.
(is (= {:name "Hubert"}
       (zipmap [:name] ["Hubert" "mrhaki"])))

;; Using a lazy sequence created by the repeat
;; function we can set a default value for all keys.
(is (= {:name "" :alias "" :city ""}
       (zipmap [:name :alias :city] (repeat ""))))

;; If we have keys with the same name the last
;; mapping ends up in the resulting map.
(is (= {:name "mrhaki"}
       (zipmap [:name :name] ["Hubert" "mrhaki"])))

;; Keys for the resulting map don't have to be keywords,
;; but can be any type.
(is (= {"name" "Hubert" "alias" "mrhaki"}
       (zipmap ["name" "alias"] ["Hubert" "mrhaki"])))

Written with Clojure 1.10.1.

Original post written on May 29, 2020

Using The range Function

In Clojure we can use the range function to create a lazy sequence of numbers. We can optionally specify a start value, end value and define the steps between the numbers. If we use the end value argument that value is exclusive for the returned values in the lazy sequence.

In the following example we invoke the range function with different arguments:

(ns mrhaki.core.range
  (:require [clojure.test :refer [is]]))

;; range function without arguments returns
;; an infinite lazy sequence of numbers.
(is (= '(0 1 2 3 4) (take 5 (range))))

;; We can specifyt the start value for 
;; a lazy infinite  sequence of numbers.
(is (= '(0 1 2 3 4) (range 5)))

;; With the second argument we set the
;; end value for our lazy sequence of numbers.
;; The end value is exclusive for the range.
(is (= '(5 6 7 8 9) (range 5 10)))

;; The third argument defines the step value
;; between numbers, which by default is 1.
(is (= '(0 2 4 6 8) (range 0 10 2)))

;; We can also have a lazy sequence counting 
;; numbers back.
(is (= '(5 4 3 2 1) (range 5 0 -1)))

(is (= '(100 97 94 91 88) (take 5 (range 100 0 -3))))

Written with Clojure 1.10.1.

Original post written on May 13, 2020

Combine First And Next Functions Multiple Times

The first function in Clojure returns the first item of a collection. The next function returns a new sequence with all elements after the first element from a collection. Clojure adds some utility methods to combine first and next with different combinations. We can use the function ffirst which is will return the first element of the first element of a collection and the nfirst function to get the next elements from the first element of a collection. We can use the function fnext to get the first element of the next elements of a collection and the function nnext to get the next elements of the next elements of a collection.

In the following example we use the ffirst, nfirst, fnext and nnext:

(ns mrhaki.seq
  (:require [clojure.test :refer [is]]))

(def langs [{:language "Clojure" :site "https://clojure.org" :dynamic true}
            {:language "Groovy" :site "https://www.groovy-lang.org" :dynamic true}
            {:language "Java" :site "https://www.java.com" :dynamic false}
            {:language "Kotlin" :site "https://kotlinlang.org" :dynamic false}])

;; Find first map entry of first map in languages.
(is (= [:language "Clojure"]
       (ffirst langs)
       (first (first langs))))

;; Find next map entries for first map in languages.
(is (= (list [:site "https://clojure.org"] [:dynamic true])
       (nfirst langs)
       (next (first langs))))

;; Find first map of next maps in languages.
(is (= {:language "Groovy" :site "https://www.groovy-lang.org" :dynamic true}
       (fnext langs)
       (first (next langs))))

;; Find next maps of next maps in languages.
(is (= (list {:language "Java" :site "https://www.java.com" :dynamic false}
             {:language "Kotlin" :site "https://kotlinlang.org" :dynamic false})
       (nnext langs)
       (next (next langs))))

Written with Clojure 1.10.1.

Original post written on April 13, 2020

Get Random Item From A Sequence

In Clojure we can use the rand-nth function to get a single random element from a sequence. To get multiple items based on random probability for each item we use the function random-sample. We must set the probability that determines for each item if it is in the result or not.

In the following example code we use rand-nth function:

(ns mrhaki.seq.random
  (:require [clojure.test :refer [is]]))

;; We use the function rand-nth to get a 
;; random element from a sequence collection.
(is (contains? #{"Clojure" "Java" "Groovy"} 
               (rand-nth ["Groovy", "Clojure", "Java"])))

;; We can use the rand-nth function with a map
;; if we first turn it into a sequence.
(is (contains? #{[:a 1] [:b 2]} (rand-nth (seq {:a 1 :b 2}))))

This next example shows how we can use the random-sample function:

(ns mrhaki.seq.random
  (:require [clojure.test :refer [is]]))

;; Using random-sample each item is in the
;; result based on the random probability of the
;; probability argument. 
;; When probability is 1 all items are returned.
(is (= ["Clojure" "Groovy" "Java"]
       (random-sample 1.0 ["Clojure" "Groovy" "Java"])))

;; When proability is 0 no item is in the result.
(is (empty? (random-sample 0 ["Clojure" "Groovy" "Java"])))

;; Any other value between 0 and 1 will return different
;; results for each invocation of the random-sample function.
(def samples (random-sample 0.4 ["Clojure" "Groovy"]))
(is (or (empty? samples)
        (= ["Clojure" "Groovy"] samples)
        (= ["Clojure"] samples)
        (= ["Groovy"] samples)))

Written with Clojure 1.10.1

Original post written on March 30, 2020

Query Set Of Maps With index Function

The namespace clojure.set has useful functions when we work with sets. One of the functions is the index function. The index function can be used for a set with map elements to create a new map based on distinct values for one or more keys. The first argument of the function is the set we transform and the second argument is a vector of one or more keys we want to index on. The keys in the new map are maps themselves. The value for each key is a set of maps that have the given keyword/value combination. The new map can be easily queried with the get function to get the values for a key.

In the next example code we see how we can use the clojure.set/index function to first transform a set with map elements to the new map and how to work with the resulting map:

(ns mrhaki.set.index
  (:require [clojure.test :refer [is]]
            [clojure.set :refer [index]]))

(def languages #{{:platform :jvm :name "Clojure"}
                 {:platform :jvm :name "Groovy"}
                 {:platform :native :name "Ruby"}
                 {:platform :jvm :name "JRuby"}
                 {:platform :native :name "Rust"}})

;; index function returns a map with a key for
;; each unique key/value combination for the keys
;; passed as second argument.
;; The value of each key is a set of the 
;; map that comply with the key/value combination.
(is (= {{:platform :jvm} #{{:platform :jvm :name "Clojure"}
                           {:platform :jvm :name "Groovy"}
                           {:platform :jvm :name "JRuby"}}
        {:platform :native} #{{:platform :native :name "Ruby"}
                              {:platform :native :name "Rust"}}}
        (index languages [:platform])))

;; We can use all collection functions on the map result
;; of the index function.
(is (= ["Clojure" "Groovy" "JRuby"]
       (map :name (get (index languages [:platform]) {:platform :jvm}))))


;; Set with sample data describing a shape
;; at a x and y location.
(def data #{{:shape :rectangle :x 100 :y 100}
            {:shape :circle :x 100 :y 100}
            {:shape :circle :x 100 :y 0}
            {:shape :circle :x 0 :y 100}})

;; We can use multiple keys as second argument of the
;; index function if we want to index on values of 
;; more thane one key.
(is (= {{:x 0 :y 100} #{{:shape :circle :x 0 :y 100}}
        {:x 100 :y 0} #{{:shape :circle :x 100 :y 0}}
        {:x 100 :y 100} #{{:shape :circle :x 100 :y 100}
                          {:shape :rectangle :x 100 :y 100}}}
       (index data [:x :y])))

(is (= #{{:shape :circle :x 100 :y 100}
         {:shape :rectangle :x 100 :y 100}}
         (get (index data [:x :y]) {:x 100 :y 100})))

Written with Clojure 1.10.1.

Original post written on July 23, 2020

Creating Union Of Sets

When we are working with sets in Clojure we can use some useful functions from the clojure.set namespace. In a previous post we learned how we can get the difference of several sets. To get the union of several input sets we use the union function of the clojure.set namespace. The function returns a new set that is the union of unique elements from the input sets. A nil value is ignored by the union function.

In the following example code we use union:

(ns mrhaki.set.union
  (:require [clojure.set :as set]
            [clojure.test :refer [is]]))

;; union return a set with elements that contains the unique
;; elements of the input sets.
(is (= #{"Java" "Clojure" "Groovy" "Kotlin"}
      (set/union #{"Java" "Clojure" "Groovy"} #{"Kotlin" "Groovy" "Clojure"})))

;; We can use multiple input sets.
(is (= #{"Java" "Clojure" "Groovy" "Kotlin"}
       (set/union #{"Java" "Clojure" "Groovy"} 
                  #{"Groovy" "Clojure"}
                  #{"Kotlin"})))

;; A nil input is ignored.
(is (= #{"Clojure" "Groovy" "Kotlin"}
       (set/union #{"Groovy" "Clojure"} nil #{"Kotlin"})))

Written with Clojure 1.10.1.

Original post written on July 2, 2020

Find Differences In Sets

If we want to get the values from a set that are not part of one or more other sets we must use the difference function in the clojure.set namespace. The function returns a set with all values from the first set that are different from values in other sets.

In the following example we use the difference with several sets:

(ns mrhaki.set.difference
  (:require [clojure.set :as set]
            [clojure.test :refer [is]]))

;; The difference function will take a first set 
;; and leave out elements that are in the following set(s).
(is (= #{"Java"}
       (set/difference #{"Java" "Clojure" "Groovy"} 
                       #{"Kotlin" "Groovy" "Clojure"})))

(is (= #{"Java"}
       (set/difference #{"Java" "Clojure" "Groovy"} 
                       #{"Kotlin" "Groovy"} 
                       #{"Clojure"})))


;; When other sets do not contain values
;; from the first set, the result is the original set.
(is (= #{1 2 3}
       (set/difference #{1 2 3} #{4 5})))

Written with Clojure 1.10.1.

Original post written on June 29, 2020

Getting But The Last Element(s) From A Collection

When we want to get elements from a collection, but not the last element(s), we can use the function butlast and drop-last. The function butlast returns all elements before the last element. If we use the function on an empty collection we get back a nil result. When we use the function drop-last we get back a lazy sequence. Also we can use an extra argument for the function to indicate how many of the last elements we don't want in the result. If we use drop-last on an emtpy collection we get back an empty lazy sequence.

In the following example we use both functions with several collections:

(ns mrhaki.core.butlast
  (:require [clojure.test :refer [is]]))

;; Sample vector with some JVM langauges.
(def languages ["Clojure" "Groovy" "Java"])

;; Sample map describing a user.
(def user {:alias "mrhaki" :first "Hubert" :last "Klein Ikkink" :country "The Netherlands"})

;; Using butlast to get all elements but 
;; not the last element as a sequence.
(is (= '("Clojure" "Groovy") (butlast languages)))

;; We can also use butlast on a map, the result
;; is a sequence with vectors containing the 
;; key/value pairs from the original map.
(is (= '([:alias "mrhaki"] [:first "Hubert"] [:last "Klein Ikkink"])
       (butlast user))
;; We can use the into function to transform this
;; into a map again.
    (= {:alias "mrhaki" :first "Hubert" :last "Klein Ikkink"}
       (into {} (butlast user))))

;; Returns nil when collection is empty.
(is (= nil (butlast [])))


;; drop-last returns a lazy sequence with all 
;; elements but the last element.
(is (= '("Clojure" "Groovy") (drop-last languages)))

;; Returns an empty sequence when collection is empty.
(is (= '() (drop-last [])))

;; We can use an extra argument with but-last
;; to indicate the number of items to drop
;; from the end of the collection.
;; butlast cannot do this.
(is (= ["Clojure"] (drop-last 2 languages)))

;; drop-last works on maps just like butlast.
(is (= '([:alias "mrhaki"]) (drop-last 3 user))
    (= {:alias "mrhaki"} (into {} (drop-last 3 user))))

Written with Clojure 1.11.1.

Original post written on October 30, 2022

Remove Duplicates From A Collection With distinct

With the function distinct we can remove duplicate elements from a collection. The function returns a lazy sequence when we use a collection argument. Without arguments the function returns a transducer. When we want to remove duplicates and we don't need the lazy sequence result we could also turn a collection into a set with for example the set or into functions.

In the following example we use the distinct function on several collections.

(ns mrhaki.core.distinct
  (:require [clojure.test :refer [is]]))

;; In the following example we have the results
;; from several throws with a dice and we want
;; to remove all duplicates.
(is (= [1 5 6 2 3] (distinct [1 5 5 6 2 3 3 1])))

;; Only duplicates are removed.
(is (= ["Clojure" "Groovy" "Java"]
       (distinct ["Clojure" "Groovy" "Java" "Java" "Java" "Clojure"])))

;; String is also a collection we can invoke distinct function on.
(is (= [\a \b \c \d \e \f] (distinct "aabccdeff")))

;; For example a collection of mouse clicks where
;; we want to get rid of duplicate clicks at the same position.
(is (= [{:x 1 :y 1} {:x 1 :y 2} {:x 0 :y 0}]
       (distinct '({:x 1 :y 1} {:x 1 :y 2} {:x 1 :y 1} {:x 0 :y 0}))))
       
;; When we don't need the sequence result with ordening we can
;; also use a set to remove duplicates. 
;; We loose the order of the elements.
(is (= #{1 5 6 2 3}
       (set [1 5 6 5 2 3 1])
       (into #{} [1 5 6 5 2 3 1])))

Written with Clojure 1.10.1.

Original post written on February 8, 2021

Remove Consecutive Duplicate Elements From Collection

The Clojure core namespace contains many functions. One of the functions is the dedupe function. This function can remove consecutive duplicates from a collection and returns a lazy sequence where only one of the duplicates remain. It will not remove all duplicate elements from the collection, but only when the element is directly followed by a duplicate element. The function returns a transducer when no argument is given.

In the following code sample we use the dedupe function on several collections:

(ns mrhaki.core.dedupe
  (:require [clojure.test :refer [is]]))

;; In the following example we have the results
;; from several throws with a dice and we want
;; remove duplicates that are thrown after another.
(is (= [1 5 6 2 3 1] (dedupe [1 5 5 6 2 3 3 1])))

;; Only consecutive duplicates are removed.
(is (= ["Clojure" "Groovy" "Java" "Clojure"]
       (dedupe ["Clojure" "Groovy" "Java" "Java" "Java" "Clojure"])))

;; String is also a collection.
(is (= [\a \b \c \d \e \f] (dedupe "aabccdeff")))

;; For example a collection of mouse clicks where
;; we want to get rid of consecutive clicks at the same position.
(is (= [{:x 1 :y 2} {:x 1 :y 1} {:x 0 :y 0}] 
       (dedupe '({:x 1 :y 2} {:x 1 :y 1} {:x 1 :y 1} {:x 0 :y 0}))))

Written with Clojure 1.10.1.

Original post written on February 5, 2021

Getting Part Of A Vector With subvec

In Clojure we can get part of a vector collection using the subvec function. The function takes a vector as argument, a required begin index and optional end index. The returned value is a vector with part of the values of the original vector starting from the begin up to the end index. If we leave out the optional end index, the size of the vector is used as end index.

In the following example we use the subvec function with and without the end index:

(ns mrhaki.core.subvec
  (:require [clojure.test :refer [is]]))

;; Vector of some JVM languages.
(def languages ["Java" "Kotlin" "Clojure" "Groovy"])

;; Using only the start index argumnt we get all items
;; from the start index to the end.
(is (= ["Clojure" "Groovy"] (subvec languages 2)))

;; When we use the start and end index arguments
;; we get the items from start to the given end.
(is (= ["Clojure"] (subvec languages 2 3)))

Written with Clojure 1.10.1.

Original post written on November 2, 2020

Shuffle A Collection

In Clojure we can use the shuffle function with a collection argument to get a new collection where the items of the input collection are re-ordered randomly. The function delegates to the Java java.util.Collections#shuffle method.

In the following example code we use the shuffle method:

(ns mrhaki.core.shuffle
  (:require [clojure.test :refer [is]]))

;; shuffle will return a new collection 
;; where the items are in a different order.
(shuffle (range 5)) ;; Possible collection [4 0 1 2 3]
(shuffle (range 5)) ;; Possible collection [1 3 4 2 0]

;; Define a deck of cards.
(def cards (for [suite  [\♥ \♠ \♣ \♦]
                 symbol (concat (range 2 11) [\J \Q \K \A])] 
             (str suite symbol)))

;; Some checks on our deck of cards.
(is (= 52 (count cards)))
(is (= (list "♥2" "♥3" "♥4" "♥5" "♥6" "♥7" "♥8" "♥9" "♥10" "♥J" "♥Q" "♥K" "♥A")
       (take 13 cards)))

;; Let's shuffle the deck. We get a new collection of cards ordered randomly.
(def shuffled-deck (shuffle cards))

;; Shuffled deck contains all items from the cards collection.
(is (true? (every? (set cards) shuffled-deck)))

;; We can take a number of cards.
(take 5 shuffled-deck) ;; Possible result: ("♦6" "♦10" "♥K" "♥4" "♥10")

;; We do a re-shuffle and get different cards now.
(take 5 (shuffle shuffled-deck)) ;; Possible result: ("♥10" "♥Q" "♦4" "♣8" "♠5")

Written with Clojure 1.10.1.

Original post written on October 11, 2020

Finding The Maximum Or Minimum Value

To find the maximum or minimum value for numeric values we can use the max and min function. The functions accept one or more numeric arguments and the value that is maximum or minimum is returned. If the numbers are already in a sequence we can use apply max or apply min. If the values are not numbers we can use the max-key or min-key functions. These functions take as first argument a function that returns a number. So we can get the value that has the maximum or minimum return value for the function we pass as first argument.

In the next exmaple code we use the max, min, max-key and min-key functions:

(ns mrhaki.core.min-max
  (:require [clojure.test :refer [is]]))

;; We can use max to find the maximum number in the given arguments.
(is (= 20 (max 10 2 3 1 20)))

;; If we have a collection we can use apply max to find the maximum number.
(is (= 20 (apply max [10 2 3 1 20])))


;; We can use min to find the minimum number in the given arguments.
(is (= 1 (min 10 2 3 1 20)))

;; And also use apply min when we have collection with numbers.
(is (= 1 (apply min [10 2 3 1 20])))


;; When the arguments are not numbers we can provide a function to get
;; back numbers and use that function with max-key to find the maximum.
(is (= "Clojure" (max-key count "Java" "Groovy" "Clojure")))
(is (= "Clojure" (apply max-key count ["Java" "Groovy" "Clojure"])))


;; And to find the minimum for non-numbered arguments we can use min-key
;; with a function to get back numbers.
(is (= "Java" (min-key count "Java" "Groovy" "Clojure")))
(is (= "Java" (apply min-key count ["Java" "Groovy" "Clojure"])))

Written with Clojure 1.10.1.

Original post written on October 6, 2020

Taking Or Dropping Elements From A Collection Based On Predicate

In Clojure we can take or drop elements from a collection based on a predicate using the functions take-while and drop-while. With the function take-while we take elements as long as the predicate returns true. Once the predicate returns false the function stops returning elements. Using the function drop-while we skip elements in the collection if the predicate returns true. If the predicate returns false the remaining elements in the collection are returned.

In the following example we use take-while and drop-while with different collection types:

(ns mrhaki.seq.take-while
  (:require [clojure.test :refer [is]]
            [clojure.string :refer [join]]))

;; Simple range of numbers to 10 to invoke
;; take-while and drop-while functions.
(def numbers (range 10))

;; Use take-while to get all number as long as
;; the number is less than 5.
(is (= [0 1 2 3 4] (take-while #(< % 5) numbers)))

;; Use drop-while to skip all numbers that are
;; less than 5, so we get all numbers from 5.
(is (= [5 6 7 8 9] (drop-while #(< % 5) numbers)))


;; String is a collection of characters so 
;; we can use take-while and drop-while.
(def s "Clojure Rocks!")

(is (= "Clojure "
       (join (take-while #(not= \R %) s))))

(is (= "Rocks!"
       (join (drop-while #(not= \R %) s))))


;; A map structure is a collection of key/value vectors, 
;; so take-while and drop-while can be used.
(def user {:name "mrhaki" :loves "Clojure" :worksAt "JDriven"})

;; Helper function to return the length of a keyword.
(defn keyword-length
  "Returns length of keyword."
  [entry] 
  (.length (name (key entry))))

(is (= {:name "mrhaki"}
       (into {} (take-while #(= 4 (keyword-length %)) user))))

(is (= {:loves "Clojure" :worksAt "JDriven"}
       (into {} (drop-while #(= (key %) :name) user))))

Written with Clojure 1.10.1.

Original post written on July 15, 2020

Partition Collection Into Sequences

Clojure has the partition, partition-all and partition-by functions to transform a collection into a list of sequences with a (fixed) number of items. We can set the number of items in each sequence by providing a number as the first argument of the partition and partition-all functions. Any remainder elements are not in the resulting list of sequences when we use partition, but are when we use partition-all. We can also specify another collection to use values from to fill up the remainder as the third argument of the partition function.\ Optionally we can specify an offset step value as a second argument using both functions. This mean a new partition sequence will start based on stepping through the original collection with the given step value.\ Finally we can use a function to define when a new partition must start with the partition-by function. Every time the function returns a new value a new partition will begin.

In the following example Clojure code we use all three functions with all possible arguments:

(ns mrhaki.core.partition
  (:require [clojure.test :refer [is]]))

;; Sample string (a sequence of characters).
(def letters "aBCdeFg")

;; First argument defines how many items are in each partition.
;; Any remainder is ignored. 
(is (= [[\a \B] [\C \d] [\e \F]] (partition 2 letters)))

;; With partition-all the remainder is part of the result.
(is (= [[\a \B] [\C \d] [\e \F] [\g]] (partition-all 2 letters)))


;; The second argument is a step offset.
(is (= [[\a \B] [\d \e]] (partition 2 3 letters)))

(is (= [[\a \B] [\d \e] [\g]] (partition-all 2 3 letters)))

(is (= [[\a \B \C] [\C \d \e] [\e \F \g]] (partition 3 2 letters)))

(is (= [[\a \B \C] [\C \d \e] [\e \F \g] [\g]] (partition-all 3 2 letters)))


;; The third argument is used to fill the last remainder partition if needed.
(is (= [[\a \B \C] [\d \e \F] [\g \! \?]] (partition 3 3 [\! \? \@] letters)))

(is (= [[\a \B \C] [\d \e \F] [\g \! \!]] (partition 3 3 (repeat \!) letters)))

;; When padding collection has not enough items, only what is available
;; is used to fill the remainder part.
(is (= [[\a \B \C] [\d \e \F] [\g \!]] (partition 3 3 [\!] letters)))


;; Using partition-by we can use a function that perfoms the split
;; when the function returns a new value.
(is (= [[\a] [\B \C] [\d \e] [\F] [\g]]
       (partition-by #(Character/isUpperCase %) letters)))

(is (= [[ 1 2 3 4] [5] [6 7 8 9] [10] [11 12 13 14]]
       (partition-by #(= 0 (mod % 5)) (range 1 15))))

Written with Clojure 1.10.1.

Original post written on April 28, 2020

Counting Frequency Of Items In A Collection

If we want to know how often an item is part of a collection we can use the frequencies function. This function returns a map where each entry has the item as key and the number of times it appears in the list as value.

In the following example Clojure code we use the frequencies function:

(ns mrhaki.core.frequencies
  (:require [clojure.test :refer [are is]]))


(def sample "Clojure is cool!")

(is (= {\space 2 \! 1 \C 1 \c 1 \e 1 \i 1 \j 1 \l 2 \o 3 \r 1 \s 1 \u 1}
       (frequencies sample))
    "Frequency of each character in sample")


(def list ["Clojure" "Groovy" "Cool" "Goodness"])

(is (= {\C 2 \G 2}
       (frequencies (map first list)))
    "Two words start with C and two with G")


(def numbers '(29 31 42 12 8 73 46))

(defn even-or-odd
  "Return string even when number is even, 
   otherwise return string odd."
  [n]
  (if (even? n)
    "even"
    "odd"))

(is (= {"odd" 3 "even" 4}
       (frequencies (map even-or-odd numbers)))
    "list numbers has 3 odd and 4 even numbers")


(def user {:user "mrhaki" :city "Tilburg" :age 46})

(is (= {java.lang.String 2 java.lang.Long 1}
       (frequencies (map type (vals user))))
    "user map has two values of type String and 1 of type Long")

Written with Clojure 1.10.1.

Original post written on April 24, 2020

Reapply Function With Iterate To Create Infinite Sequence

The iterate function create a lazy, infinite sequence based on function calls. The iterate function takes a function and an initial value as arguments. The first element in the sequence is the initial value, next the function is invoked with the previous element as argument and this continues for each new element. Suppose we have a function #(+ 2 %) that adds 2 to the input argument. Then if we use this function with iterate and start with value 1 the first elements of the sequence will be 1, (+ 2 1), (+ 2 3), (+ 2 5). So first element is the initial value, next element is the invocation of the function with input argument 1. The result of this function is 3, which is then the input for the function to calculate the next element and so on.

In the following example code we use iterate in different scenario's:

(ns mrhaki.core.iterate
  (:require [clojure.test :refer [is]]))

;; Lazy sequence of numbers in steps of 2.
(def odds (iterate #(+ 2 %) 1))

(is (= (list 1 3 5 7 9 11 13 15 17 19)
       (take 10 odds)))


;; Define lazy sequence with a growing string.
;; The first element is ar, next argh, then arghgh etc.
(def pirate (iterate #(str % "gh") "ar"))

(def crumpy-pirate (nth pirate 5))

(is (= "arghghghghgh" crumpy-pirate))


;; Function that returns the given amount
;; plus interest of 1.25%.
(defn cumulative-interest
  [amount]
  (+ amount (* 0.0125 amount)))

;; Lazy sequence where each entry is the 
;; cumulative amount with interest based 
;; on the previous entry. 
;; We start our savings at 500.
(def savings (iterate cumulative-interest 500))

;; After 5 years we have:
(is (= 532.0410768127441
       (nth savings 5)))


;; Function to double a given integer
;; and return as bigint.
(defn doubler [n] (bigint (+ n n)))

;; Define lazy infinite sequence
;; where each element is the doubled value
;; of the previous element.
(def wheat-chessboard (iterate doubler 1))

;; First elements are still small.
(is (= (list 1 2 4 8 16 32)
       (take 6 wheat-chessboard)))

;; Later the elements grow much bigger.
(is (= (list 4611686018427387904N 9223372036854775808N)
       (->> wheat-chessboard (drop 62) (take 2))))

;; Sum of all values for all chessboard squares
;; is an impressive number.
(is (= 18446744073709551615N 
       (reduce + (take 64 wheat-chessboard))))

Written with Clojure 1.10.1.

Original post written on April 16, 2020

Checking Predicate For Every Or Any Element In A Collection

In Clojure we can use several functions to see if at least one or all elements in a collection return true or false for a predicate. The function every? only returns true if the predicate function returns true for all elements in the collection. To function not-every? return true if a predicate function return false for all elements in a collection. The some function is a bit different (notice there is no ?) and returns the first logical true value from the predicate function for the elements in the collection. So the return type of the predicate doesn't have to be a Boolean value and then the return type of some is also not a Boolean. If the predicate returns a Boolean value we can use some like a any function (any is not part of Clojure). Clojure provides a not-any? function that returns true if the predicate function returns false for one element in the collection and false otherwise.

The following example uses the different functions on a vector with some cartoon names:

(ns mrhaki.seq.pred
  (:require [clojure.test :refer [is]]
            [clojure.string :as str]))

;; Vector of toons to check predicates on.
(def toons ["Daffy Duck" "Bugs Bunny" "Elmer Fudd" "Yosemite Sam"])

;; Helper function to count number of names.
(defn count-names
  [name]
  (count (str/split name #" ")))

;; Every toon has two names.
(is (true? (every? #(= 2 (count-names %)) toons)))

;; Not every toon name starts with "A".
(is (true? (not-every? #(str/starts-with? "A" %) toons)))


;; Helper function to check if the first letter
;; of both names is the same.
(defn same-first-letters?
  [name]
  (let [names (str/split name #" ")
        first-letter (first (first names))
        second-letter (first (second names))]
    (= first-letter second-letter)))

;; Some toons have the same first letter
;; for their first and last name.
(is (true? (some same-first-letters? toons)))

;; Using set as function to check toon is in the toons vector.
;; Notice some function return the first value from the predicate function
;; that is not nil or false, instead of a boolean like with
;; every?, not-every? and not-any?.
(is (not (true? (some #{"Yosemite Sam", "Road Runner"} toons))))
(is (= "Yosemite Sam" (some #{"Yosemite Sam", "Road Runner"} toons)))

;; As seen on https://clojuredocs.org/clojure.core/any_q a
;; possible implementation for any that returns true or false.
(defn any [pred coll] ((comp boolean some) pred coll))
(is (true? (any #{"Yosemite Sam", "Road Runner"} toons)))

;; There is a toon name where their name length is 10.
(is (false? (not-any? #(= (count %) 10) toons)))

Written with Clojure 1.10.1.

Original post written on April 8, 2020

Keep Non-Nil Function Results From Collection

The keep function in Clojure invokes a function on each item in a collection and only returns non-nil results from the function invocation. The result of the keep function is a lazy sequence.

The following example uses the keep function, but also show what results would be when using map function on the same collection with the same function argument:

(ns mrhaki.seq.keep
  (:require [clojure.test :refer [is]]))

(def stuff ["Clojure" "Groovy" "Java"])

;; Function keep filters on non-nil results that are returned
;; from applying the function. 
(is (= '("Clojure has more than 6 characters")
       (keep #(if (> (count %) 6) (str % " has more than 6 characters")) stuff)))

;; Using the same function with map shows the
;; nil results that are filtered by keep.
(is (= (list "Clojure has more than 6 characters" nil nil)
       (map #(if (< 6 (count %)) (str % " has more than 6 characters")) stuff)))


(def user {:name "Hubert" :nickname "mrhaki" :age 46})

;; Returned result from the function is a boolean
;; so it is always included in the result after applying 
;; the keep function.
(is (= [true true false]
       (keep #(instance? String (% 1)) user)))

;; Here the function returns a string result or nill.
(is (= [":name has a String value" ":nickname has a String value"]
       (keep (fn [[k v]] (if (instance? String v) (str k " has a String value"))) user)))

Written with Clojure 1.10.1.

Original post written on April 2, 2020

Flatten Collections

We can use the flatten function when we have a collection with nested sequential collections as elements and create a new sequence with the elements from all nested collections.

In the following example we use the flatten function:

(ns mrhaki.sample
  (:require [clojure.test :refer [is]]))

;; Elements from nested sequential collections are flattend into new sequence.
(is (= [1 2 3 4 5] (flatten [1 [2 3] [[4]] 5])))
(is (sequential? (flatten [1 [2 3] [[4]] 5])))
(is (= [1 2 3 4 5] (flatten [[1] [2 3] [[4 5]]])))

;; We can use different sequential collection types.
;; We might have to force a type to a sequential collection with seq.
(is (= '(1 2 3 4 5) (flatten [1 (seq (java.util.List/of 2 3)) ['(4 5)]])))
(is (= (quote (1 2 3 4 5)) (flatten [[1] [(range 2 6)]])))

;; flatten on nil returns empty sequence.
(is (= () (flatten nil)))

Written with Clojure 1.10.1.

Original post written on January 10, 2020

Getting Intersections Between Sets

In the clojure.set namespace we can find the intersection function. This functions accepts one or more sets as arguments and return a new set with all elements that are present in the sets that are passed as arguments to the intersection function. The argument must be a set, so we need to convert other collection or seq values to a set first before we use it as an argument for the function.

In the following example we use one, two or three arguments for the intersection function and also convert other types to a set to be used as argument:

(ns mrhaki.sample
  (:require [clojure.set :refer [intersection]]
            [clojure.test :refer [is]]))

;; Use intersection with sets to find common elements.
(is (= #{"Clojure"} (intersection #{"Java" "Scala" "Clojure"} #{"Clojure" "Groovy"})))

;; An empty set is returned if there is no common element.
(is (= #{} (intersection #{"Java" "Groovy" "Clojure"} #{"C++" "C#"})))

;; We can use more than two sets to find intersections.
(is (= #{"Clojure"} (intersection #{"Java" "Scala" "Clojure"} 
                                  #{"Clojure" "Groovy"} 
                                  #{"Groovy" "JRuby" "Clojure"})))

;; With one set intersections returns the set.
(is (= #{"Clojure" "Groovy"} (intersection #{"Clojure" "Groovy"})))

;; Only sets are allowed as arguments for the intersection function.
;; If one of the arguments is not a set the return value is unexpected. 
(is (= #{} (intersection #{"Clojure" "Groovy"} ["Java" "Scala" "Clojure"])))
;; But we can convert a non-set to a set with the set function.
(is (= #{"Clojure"} (intersection #{"Clojure" "Groovy"} (set ["Java" "Scala" "Clojure"]))))
(is (= #{"Clojure"} (intersection #{"Clojure" "Groovy"} (set '("Java" "Scala" "Clojure")))))
;; Or using into #{}.
(is (= #{"Clojure"} (intersection #{"Clojure" "Groovy"} 
                                  (into #{} (vals {:platform "Java" :language "Clojure"})))))

Written with Clojure 1.10.1

Original post written on January 8, 2020