ts.
ts.

Reputation: 10709

reversing hash map in clojure

I've hash-map in clojure:

{"key1" "value1"} {"key2" "value2"} {"key3" "value1"}

and i need to convert it into hash map of

{"value1" {"key1" "key3"}} {"value2" {"key2"}}

Any clojure way of doing this?

clojure.set/map-invert will not work as if it overrides repeated values.

Upvotes: 3

Views: 496

Answers (5)

Óscar López
Óscar López

Reputation: 236094

Give this a try:

(def m {"key1" "value1" "key2" "value2" "key3" "value1"})

(reduce (fn [a x] (assoc a (second x) (conj (a (second x)) (first x)))) {} m)
=> {"value2" ("key2"), "value1" ("key3" "key1")}

Notice that the (possibly) repeated values end up in a list. Or, as suggested by @A.Webb in the comments, the above can be concisely written like this:

(reduce (fn [a [k v]] (update-in a [v] conj k)) {} m)
=> {"value2" ("key2"), "value1" ("key3" "key1")}

Upvotes: 2

Michiel Borkent
Michiel Borkent

Reputation: 34840

(def m {"key1" "value1" "key2" "value2" "key3" "value1"})

(let [g (group-by val m)
      vals (map #(map first %) (vals g))]
  (zipmap (keys g) vals))
;;=> {"value2" ("key2"), "value1" ("key1" "key3")}

Upvotes: 5

JohnJ
JohnJ

Reputation: 4833

Here's another alternative:

(def maps [{"key1" "value1"} {"key2" "value2"} {"key3" "value1"}])

(into {} 
  (for [[k v] (group-by #(val (first %)) maps)] 
    [k (apply concat (map keys v))]))

;=> {"value1" ("key1" "key3"), "value2" ("key2")}

Upvotes: 1

Abimaran Kugathasan
Abimaran Kugathasan

Reputation: 32478

Try the following, I don't have REPL to test, it may slightly differ from the original answer, but, you can use it to get what you want.

(group-by #(val (first %)) {"key1" "value1"} {"key2" "value2"} {"key3" "value1"})

Upvotes: 1

Ankur
Ankur

Reputation: 33657

Your question is really confusing. First you said you have hash-map, what you actually have as example is many hash-maps or if you really mean a single hash-map then your example is incorrect as it should be {"key1" "value1" "key2" "value2" "key3" "value1"}. Second, the required output is weird in the sense that the values in the hash-map are represented as maps themselves but the last value is just a single value in a hash-map which is obviously not possible, so I guess you mean the values are set (not map) as {"value1" #{"key1" "key3"}} {"value2" #{"key2"}}

Based on all these assumptions one possible solution would be:

(->> {"key1" "value1" "key2" "value2" "key3" "value1"}
     (group-by second)
     (map #(-> [(%1 0) (into #{} (map first (%1 1)))]))
     (into {}))

Upvotes: 1

Related Questions