07.07.12
Clojure deep-update-in
I needed this the other day and wondered if it would help others or if there’s a better way.
There are two functions. The first goes looking for a key anywhere in a map and produces a sequence of key-paths that can be used with get-in, update-in and assoc-in. Note this code only recurses into substructures that are vectors or maps.
(defn find-key [ks k m]
(cond (map? m)
(reduce into (map (partial conj ks) (filter #{k} (keys m)))
(map #(find-key (conj ks (key %)) k (val %)) m))
(vector? m)
(reduce into '() (map #(find-key (conj ks %1) k %2)
(iterate inc 0) m))))
The deep-update-in uses the above:
(defn deep-update-in [m k f]
(reduce #(update-in %1 %2 f) m (find-key [] k m)))
m is the map, k the leaf key you're looking for (a single key, not a path of keys), and f the function you want to do the update.