Just use maps






cycognito



clojure logo

Topics

  • The benefits of programming with maps

  • Keywords in maps

  • Accessing values in a map

  • Map as a sequence

  • Mapping over a map

    • Mapping the keys

    • Mapping the values

  • Filtering over a map

  • Immutable maps

  • Mutable maps

The benefits of programming with maps

  • Maps are generic

  • Maps are flexible

Keywords in maps

Keyword is the most commonly used type for fields

(def person
      {:first-name "Joe"
         :last-name "Cohen"})

Keywords behave like functions

(:first-name person)

Accessing values in a nested map

(def config
  {:server {:port 5432}
  :db {:collection "sales"}})

Passing the path

(get-in config [:db :collection])

Map as a sequence

In terms of data, a map is a sequence of pairs

(seq {:first-name "Joe"
                  :last-name "Cohen"})

All the sequence functions work on map

(first {:first-name "Joe"
                  :last-name "Cohen"})

Map entries look like vectors but they have their own type

(type (first {:first-name "Joe"
                  :last-name "Cohen"}))

Mapping over map

Mapping the keys

(into {} (map (fn [[k v]]
                [(name k) v])
              {:first-name "Joe"
               :last-name "Cooker"}))

Mapping the values

(into {} (map (fn [[k v]]
                [k (keyword v)])
              {:first-name "Joe"
               :last-name "Cooker"}))

Filtering a map

Selecting a subset of keys

(select-keys (zipmap [1 2 3 4] ["a" "b" "c" "d"])
  [1 3])

Filtering the entries that match a predicate

(into {} (filter (fn [[k v]]
                (even? v))
              (zipmap (range 10) (range 10))))

Maps are immutable

Functions that seem to change a map, returns in fact a new version of the map

(def new-person (assoc person :first-name "Frank"))
[person new-person]

There is a mutable version of maps

(def mutable-person (transient person))
(assoc! mutable-person :first-name "David")
(persistent! mutable-person)

Position of the map as an argument

  1. Functions that treat the map as a sequence receive the map as last argument

  2. Functions that treat the map as a concrete collection receive the map as first argument

Data manipulation mini pipeline

(->> (zipmap [1 2 3 4] ["a" "b" "c" "d"])
  (filter (fn [[k v]] (even? k)))
  (map (fn [[k v]] [(inc k) v]))
  (into {}))

Consecutive changes to a map

(-> (zipmap [1 2 3 4] ["a" "b" "c" "d"])
  (assoc 1 "AAA")
  (assoc 2 "BBB"))

Homework

  1. Write a function map-vals that receives a function and a map and return a map where the values are transformed by the function.

  2. Write a function compactize-map that removes entries with nil values from a map

  3. Write a function compactize-map-recursive that recursively removes entries with nil values from a map

  4. Write a function submap? that checks if m1 is a submap of m2. Map m1 is a submap of m2 if all key/value pairs in m1 exist in m2.