Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I merge within a nested hashmap?

Tags:

clojure

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?

like image 595
stuwest Avatar asked Mar 26 '14 12:03

stuwest


People also ask

How do I access nested HashMap?

You can do it like you assumed. But your HashMap has to be templated: Map<String, Map<String, String>> map = new HashMap<String, Map<String, String>>(); Otherwise you have to do a cast to Map after you retrieve the second map from the first.

How can I combine two HashMap objects containing the different types?

Assuming that both maps contain the same set of keys, and that you want to "combine" the values, the thing you would be looking for is a Pair class, see here for example. You simply iterate one of the maps; and retrieve values from both maps; and create a Pair; and push that in your result map.

How does nested HashMap compare to Java?

Comparing Nested HashMaps We can compare them using the equals() method. The default implementation compares each value.

Can we merge two maps?

The Map. putAll() method provides a quick and simple solution to merge two maps. This method copies all key-value pairs from the second map to the first map. Since a HashMap object can not store duplicate keys, the Map.


1 Answers

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.

like image 68
A. Webb Avatar answered Oct 20 '22 19:10

A. Webb