Skip to content
AgileLogics
6 min read

Maps

Prerequisites: Lists and vectors

A map associates keys with values. It's the main way to represent information in Clojure — where other languages define a class, Clojure uses a map.

(def user {:name "Ada" :age 36 :city "London"})

(println (:name user))
(println (get user :age))
(println (user :city))                 ; a map is a function of its keys
(println (get user :email "n/a"))
(println (count user))
(println (keys user))
(println (vals user))
(println (contains? user :age))
Ada
36
London
n/a
3
(:name :age :city)
(Ada 36 London)
true

Keywords are the usual keys, but any value can be a key: {"id" 1, 42 "answer", [0 0] :origin}.

"Changing" a map

(def stock {:apples 3})

(println (assoc stock :pears 5))
(println (assoc stock :apples 10 :plums 2))
(println (dissoc {:a 1 :b 2} :a))
(println (update stock :apples inc))
(println (update stock :apples + 10))
(println (merge {:a 1 :b 2} {:b 20 :c 30}))
(println (select-keys {:a 1 :b 2 :c 3} [:a :c]))
(println stock)
{:apples 3, :pears 5}
{:apples 10, :plums 2}
{:b 2}
{:apples 4}
{:apples 13}
{:a 1, :b 20, :c 30}
{:a 1, :c 3}
{:apples 3}
  • assoc adds or replaces keys; dissoc removes them.
  • update applies a function to the current value — (update m :k inc).
  • merge combines maps; later values win.
  • As always, stock itself never changed.

Looping over a map

(def prices {:coffee 3.5 :tea 2.8 :cake 4.2})

(doseq [[item price] prices]
  (println (name item) "costs" price))

(println (into {} (map (fn [[k v]] [k (* v 2)]) prices)))
(println (update-vals prices #(* % 2)))
(println (reduce + (vals prices)))
coffee costs 3.5
tea costs 2.8
cake costs 4.2
{:coffee 7.0, :tea 5.6, :cake 8.4}
{:coffee 7.0, :tea 5.6, :cake 8.4}
10.5

A map is a sequence of [key value] entries. [item price] in doseq pulls each entry apart (destructuring, covered fully in Level 2). update-vals (Clojure 1.11+) transforms every value.

Order

Small maps (up to 8 entries) happen to keep insertion order; larger ones don't. Never rely on map order — use sorted-map when you need keys sorted:

(println (sorted-map :c 3 :a 1 :b 2))
(println (into (sorted-map) {:zeta 1 :alpha 2}))
{:a 1, :b 2, :c 3}
{:alpha 2, :zeta 1}

Practice

Count how many times each word appears in "a b a c b a" and print the result.

Show solution
(require '[clojure.string :as str])

(def words (str/split "a b a c b a" #" "))
(println (reduce (fn [counts w] (update counts w (fnil inc 0))) {} words))
(println (frequencies words))
{a 3, b 2, c 1}
{a 3, b 2, c 1}

(fnil inc 0) is inc, but treats a missing (nil) count as 0. The built-in frequencies does the whole job.