A simple macro to get deeply nested values in maps
I hate it when I have to write a lot of code to do simple things. Recently I had to write some code to get a value in a deeply nested associative structure. Consider the following example:
(def complex-object
{:foo {:bar {:baz {:qux "deep inside"}}}})
The immediately obvious solution is a pain:
(def complex-object
{:foo {:bar {:baz {:qux "deep inside"}}}})
(get (get (get (get complex-object :foo) :bar) :baz) :qux)
;; => deep inside
However a smart clojurian quickly notices that he can use the awesome ->
macro to simplify things:
(def complex-object
{:foo {:bar {:baz {:qux "deep inside"}}}})
(-> complex-object
(get :foo)
(get :bar)
(get :baz)
(get :qux))
;; => deep inside
But that’s still way to long. Can we do better? Sure we can:
(def complex-object
{:foo {:bar {:baz {:qux "deep inside"}}}})
(get-in complex-object [:foo :bar :baz :qux])
;; => deep inside
Now this is much better. Still I though I would write my own macro just for the fun of it, so here you go:
(defmacro inside
[sym]
(let [args (clojure.string/split (str sym) #"\.")
head (symbol (first args))
ks (map keyword (rest args))]
(concat `(-> ~head) (map (fn [k] `(get ~k)) ks))))
;; Now you can do awesome things like:
(inside x.foo.bar.baz.qux)
;; => "deep inside"
Voila! A simple macro to make you code a bit nicer and avoid boilerplate.