Reputation: 928
I have a nested hashmap with a structure something like the following:
(def pathmap {:order {:genus {:species {:cat2 "data", :cat1 "data"}}}})
What I need is a function like assoc-in that will allow me to add new key-value pairs to the innermost nested map rather than simply replacing what's already there. For example:
(my-assoc-merge pathmap [:order :genus :species] {:cat3 "data"})
;=> {:order {:genus {:species {:cat3 "data" :cat2 "data", :cat1 "data"}}}}
I thought I might be able to do this easily enough by altering the assoc-in function slightly to use merge-with and union:
(defn my-assoc-merge
[m [k & ks] v]
(if ks
(assoc m k (my-assoc-merge (get m k) ks v))
(assoc m k (merge-with clojure.set/union (get m k '{}) v))))
Unfortunately this gives me the error "CompilerException java.lang.UnsupportedOperationException: count not supported on this type: Keyword, compiling:(core.clj:34:12)". Where am I going wrong?
Upvotes: 5
Views: 1624
Reputation: 26446
Actually, assoc-in
already creates a new key if it does not exist. Usage is as follows:
(def pathmap {:order {:genus {:species {:cat2 "data", :cat1 "data"}}}})
(assoc-in pathmap [:order :genus :species :cat3] "data")
;=> {:order {:genus {:species {:cat2 "data", :cat3 "data", :cat1 "data"}}}}
If you prefer to merge a new map, use update-in
with merge
(update-in pathmap [:order :genus :species] merge {:cat3 "data"})
;=> {:order {:genus {:species {:cat2 "data", :cat3 "data", :cat1 "data"}}}}
The problem with your my-assoc-merge
is the union
which works on sets. Change merge-with
to merge
and drop the union
.
Upvotes: 5