Find Value of Specific Key in Nested Map

Clojure offers tree-seq to do a depth-first traversal of any value. This will simplify the logic needed to find your nested key:

(defn find-nested
  [m k]
  (->> (tree-seq map? vals m)
       (filter map?)
       (some k)))

(find-nested {:a {:b {:c 1}, :d 2}} :c)
;; => 1

Also, finding all matches becomes a matter of replacing some with keep:

(defn find-all-nested
  [m k]
  (->> (tree-seq map? vals m)
       (filter map?)
       (keep k)))

(find-all-nested {:a {:b {:c 1}, :c 2}} :c)
;; => [2 1]

Note that maps with nil values might require some special treatment.


Update: If you look at the code above, you can see that k can actually be a function which offers a lot more possibilities:

  • to find a string key:

    (find-nested m #(get % "k"))
    
  • to find multiple keys:

    (find-nested m #(some % [:a :b]))
    
  • to find only positive values in maps of integers:

    (find-nested m #(when (some-> % :k pos?) (:k %)))
    

If you know the nested path then use get-in.

=> (get-in m [:a :d :f])
=> "f"

See here for details: https://clojuredocs.org/clojure.core/get-in

If you don't know the path in your nested structure you could write a function that recurses through the nested map looking for the particular key in question and either returns its value when it finds the first one or returns all the values for :f in a seq.