Clojure Koans 6 Maps Notebook

We're back for the 6th notebook on the Clojure Koans. Today's Koans focus on the topic of maps, also called "hash maps", in Clojure.

As always, spoilers lie ahead. Try and solve the Koans first on your own if you haven't yet already.

Otherwise, welcome, and I hope you find my notebook educational and/or entertaining ;)

{:deps {org.clojure/clojure {:mvn/version "1.10.1"}
        ;; complient is used for autocompletion
        ;; add your libs here (and restart the runtime to pick up changes)
        compliment/compliment {:mvn/version "0.3.9"}}}
deps.edn
Extensible Data Notation
{:hello (clojure-version)}
0.1s
Clojure
;; "Don't get lost when creating a map"
(= {:a 1 :b 2} (hash-map :a 1 :b 2))
;; skill 6001: Make a hashmap by using the `hash-map` function
0.1s
Clojure
;; "A value must be supplied for each key"
(= {:a 1} (hash-map :a 1))
0.0s
Clojure
;; "The size is the number of entries"
(= 2 (count {:a 1 :b 2}))
;; skill 6002: Measure the number of key-value pairs in a hashmap by using the `count` function.
0.0s
Clojure
;; "You can look up the value for a given key"
(= 2 (get {:a 1 :b 2} :b))
;; skill 6003: Look up the value for a given key using the `get` function
0.0s
Clojure
;; "Maps can be used as functions to do lookups"
(= 1 ({:a 1 :b 2} :a))
;; skill 6004: Use a hashmap itself as a function with a key argument to look up a value
0.0s
Clojure
;; "And  so can keywords"
(= 1 (:a {:a 1 :b 2}))
;; skill 6005: Use a key of a hashmap as a function with a hashmap argument to look up a value
0.1s
Clojure
;; "But map keys need not be keywords"
(= "Sochi" ({2010 "Vancouver" 2014 "Sochi" 2018 "PyeongChang"} 2014))
0.0s
Clojure
;; "You may not be able to find an entry for a key"
(= nil (get {:a 1 :b 2} :c))
0.0s
Clojure
;; "But you can provide your own default"
(= :key-not-found (get {:a 1 :b 2} :c :key-not-found))
;; skill 6006: Provide default return value to the `get` function for when a key cannot be located.
0.0s
Clojure
;; "You can find out if a key is present"
(= true (contains? {:a nil :b nil} :b))
;; skill 6007: Determine whether a key is present or missing in a hashmap with the `contains?` function
0.0s
Clojure
;; "Or if it is missing"
(= false (contains? {:a nil :b nil} :c))
;; skill 6008: Determine whether a key is present or missing in a hashmap with the `contains?` function
0.0s
Clojure
;; "Maps are immutable, but you can create a new and improved version"
(= {1 "January" 2 "February"} (assoc {1 "January"} 2 "February"))
;; skill 6009: "Add" key-value pairs to a Clojure hashmap by creating a new hashmap using the `assoc` function
0.0s
Clojure
;; "You can also create a new version with an entry removed"
(= {1 "January"} (dissoc {1 "January" 2 "February"} 2))
;; skill 6010 "Remove" key-value pairs from a Clojure hashmap by creating a new hashmap using the `dissoc` function
0.0s
Clojure
;; "Create a new map by merging"
(= {:a 1 :b 2 :c 3} (merge {:a 1 :b 2} {:c 3}))
;; skill 6011: Combine two hashmaps by using the `merge` function
0.0s
Clojure
;; "Specify how to handle entries with same keys when merging"
(= {:a 1 :b 2 :c 3} (merge-with + {:a 1 :b 1} {:b 1 :c 3}))
;; skill 6012: Combine two hashmaps and specify which function to reduce (?) valus for matching keys with `merge-with` function
0.0s
Clojure
;; "Often you will need to get the keys, but the order is undependable"
(= (list 2010 2014 2018)
   (sort (keys {2014 "Sochi" 2018 "PyeongChang" 2010 "Vancouver"})))
;; skill 6013: Get a sorted list of keys from a hashmap by using the `keys` and `sort` functions
0.0s
Clojure
;; "You can get the values in a similar way"
(= (list "PyeongChang" "Sochi" "Vancouver")
   (sort (vals {2010 "Vancouver" 2014 "Sochi" 2018 "PyeongChang"})))
;; skill 6014: Get a sorted list of values from a hashmap by using the `vals` and `sort` functions
0.0s
Clojure
;; "You can even iterate over the map entries as a seq"
(= {:a 2 :b 3}
   (into {}
         (map
          (fn [[k v]] [k (inc v)])
          {:a 1 :b 2})))
;; skill 6015: Iterate over and "mutate" hashmap entries as a sequence by using the `map` and `into` functions to get a hashmap result.
;; question 6001: What is the `into` function doing here on both a high level (intent/purpose) and low level (mechanics/process)?
;;           answer 6001: (validated guess --> CORRECT) Because the `map` function (in conjunction with its passed functional argument) converts the hashmap into a list of vectors (?), the `into` function is necessary to convert the entire collection back into a hashmap.
;;           proof 6001: (map (fn [[k v]] [k (inc v)]) {:a 1 :b 2})
;;                  ;; => ([:a 2] [:b 3])
;;                  (into {} `insert line of code from above`)
;;                  ;; => {:a 2, :b 3}
Clojure
Runtimes (1)