Clojure Hashmaps - thelastmile/FreeCodeCamp GitHub Wiki

Clojure Hashmaps

A hashmap is a collection that maps keys to values. They have various names in other languages; Python refers to them as dictionaries, and Javascript's objects essentially work like hashmaps.

A hashmap can, like many collections, be constructed in two ways. There is the constructor function:

;; Note that each argument is *prepended* to the hashmap, not appended.
(def a-hashmap (hash-map :a 1 :b 2 :c 3))
a-hashmap
; => {:c 3, :b 2, :a 1}

You can also define them using a hashmap literal. This is often more concise and clear. Using commas to separate key/value pairs in hashmaps is recommended, as it can make the boundaries more clear.

;; This hashmap is actually in the right order, unlike the one above.
(def another-hashmap {:a 1, :b 2, :c 3})
another-hashmap
; => {:a 1, :b 2, :c 3}

Keywords and retrieving values from hashmaps

Hold up. What is this? :a? :b? :c? Those look odd. Those, you see, are keywords. They're called key-words because they're often used as keys in hashmaps.

Why are they often used as keys? Well, unlike strings, keywords can be used as functions to extract values from a hashmap; no need for get or nth!

(def string-hashmap {"a" 1, "b" 2, "c" 3})
("a" string-hashmap)
; => ClassCastException java.lang.String cannot be cast to clojure.lang.IFn

(def keyword-hashmap {:a 1, :b 2, :c 3})
(:a keyword-hashmap)
; => 1

;; You can also pass a keyword a default value in case it's not found, just like get.
(:not-in-the-hashmap keyword-hashmap "not found!")
; => "not found!"

Converting other collections to hashmaps

Converting to a hashmap is tricky. To demonstrate, let's try using it like vec or seq.

(hash-map [:a 1 :b 2 :c 3])
; => IllegalArgumentException No value supplied for key: [:a 1 :b 2 :c 3]

The hash-map function thinks that we're trying to create a hashmap with [:a 1 :b 2 :c 3] as one of the keys. Watch what happens if we give it the right number of arguments:

(hash-map [:a 1 :b 2 :c 3] "foo")
; => {[:a 1 :b 2 :c 3] "foo"}

To convert a sequence to a hashmap, you'll need to use and understand apply. Luckily, this is pretty simple: apply essentially destructures a collection before applying a function to it.

;; These two expressions are exactly the same.
(+ 1 2 3)
; => 6
(apply + [1 2 3])
; => 6

This is how you would convert a vector to a hashmap:

(apply hash-map [:a 1 :b 2 :c 3])
; => {:c 3, :b 2, :a 1}

;; This is the same as:
(hash-map :a 1 :b 2 :c 3)
; => {:c 3, :b 2, :a 1}

:rocket: IDEOne it!

Update a hashmap

You can update values inside a hashmap using assoc. This allows you to append new key/value pairs or change old ones.

(def outdated-hashmap {:a 1, :b 2, :c 3})

(def newer-hashmap (assoc outdated-hashmap :d 4))
newer-hashmap
; => {:a 1, :b 2, :c 3, :d 4}

(def newest-hashmap (assoc newer-hashmap :a 22))
newest-hashmap
; => {:a 22, :b 2, :c 3, :d 4}

;; Note that outdated-hashmap has not been mutated by any of this.
;; Assoc is pure and functional.
outdated-hashmap
; => {:a 1, :b 2, :c 3}

When to use a hashmap?

A hashmap is useful when you want to give names to your variables. If you're ever thinking to yourself, "What if I used an object..." before you snap out of it and realise you're using Clojure, try using a hashmap.

They are also useful if you want to associate two different values with each other. Take, for example, a ROT13 cipher: you could associate \A with \N, \B with \M, etc. (This would be long and boring to write in most languages, but Clojure has some functions that can generate it for you and make it fun!)

:point_left: Previous :book: Home :book: Next :point_right:
Vectors Table of Contents To Be Added