typestar

Nested map updates in Clojure

Reads and rewrites a two-level tool inventory through key paths instead of hand-nested calls.

;; get-in walks a path of keys through nested maps and returns a
;; default when the path runs out early.
(def inventory
  {:tools {:hammer {:on-hand 4 :bin "A1"}
           :chisel {:on-hand 0 :bin "A3"}}})

(println (format "hammers %d" (get-in inventory [:tools :hammer :on-hand])))
(println (format "bolts %d" (get-in inventory [:parts :bolt :on-hand] 0)))

;; assoc-in writes a value at a path, building maps along the way.
;; update-in instead applies a function to whatever sits there, with
;; any extra arguments passed after the current value.
(def stocked (assoc-in inventory [:tools :chisel :on-hand] 6))
(def sold (update-in stocked [:tools :hammer :on-hand] - 3))
(def moved (update-in sold [:tools :chisel :bin] str "-back"))

(println (format "hammers now %d, chisel bin %s"
                 (get-in sold [:tools :hammer :on-hand])
                 (get-in moved [:tools :chisel :bin])))

How it works

  1. (get-in inventory [:tools :hammer :on-hand]) walks a path of keys, and the trailing 0 in the bolts lookup is the default when the path is missing.
  2. (assoc-in inventory [:tools :chisel :on-hand] 6) writes a value at the path and returns a new map.
  3. (update-in stocked [:tools :hammer :on-hand] - 3) applies - to the count already there, passing 3 as an extra argument.

Keywords and builtins used here

The run, in numbers

Lines
19
Characters to type
855
Tokens
130
Three-star pace
65 tpm

At the three-star pace of 65 tokens a minute, this run takes about 120 seconds.

Type this snippet

Step 2 of 3 in State & records, step 23 of 27 in Language basics.

← Previous Next →