Let's return to our char-type function, and this time we'll add a few more things to it:
(def digits #{\1 \2 \3 \4 \5 \6 \7 \8 \9 \0}) (defn char-type [ch] (cond (contains? digits ch) :digit (= ch \space) :space (= ch \.) :period (= ch \/) :forward-slash (= ch \") :double-quote true :other))
Let's map over the characters to see how it looks with the new additions:
(def chars (vec "42 0.5 1/2 foo-bar")) (map char-type chars)
Notice that most of these branches are just comparing the argument to a single character, and returning a keyword that names it. In Clojure, we can store these simple key-value pairs more elegantly in a hash map:
(def char-names {\space :space \. :period \/ :forward-slash \" :double-quote})
We can now look up a given character using get:
(get char-names \.)
And we can also use contains? to check if a given key is in it:
(contains? char-names \")
With that, we can rewrite char-type to read from our hash map if it contains the character:
(defn char-type [ch] (cond (contains? digits ch) :digit (contains? char-names ch) (get char-names ch) true :other))
And we can see that it works the same way:
(map char-type chars)
We've already seen vectors, sets, and lists. Hash maps are the fourth major data structure in Clojure. Unlike the example above, most hash maps use keywords as their keys, like this:
(def person {:name "Bob" :age 33 :country "United States"})
When done this way, we don't even need to call (get person :name) to get the name. Keywords can actually act as functions directly:
(:name person)
Nonetheless, in our char-names hash map, we need to call get, because our keys are characters.