Reputation: 1111
I am trying to create a kind of a reverted index from an input map
. The input map I got is:
{"id-1" {"values" ["a" "b" "c"]}, "id-2" {"values" ["a" "b" "c"]}}
Then I want to have this other map as result:
{"a" ["id-1" "id-2"], "b" ["id-1" "id-2"], "c" ["id-1" "id-2"]}
However, I think that my mind did go crazy, and I think I painted myself into the corner without being able of thinking out of the box. Here is what I got so far, and it looks like that it stinks:
(->> {"id-1" {"values" ["a" "b" "c"]} "id-2" {"values" ["a" "b" "c"]}}
(map #(->> (get (second %) "values")
(map (fn [x y] (hash-map y x)) (into [] (repeat (count (get (second %) "values")) (first %))))
(apply merge-with concat)))
(apply merge-with concat))
Basically, I use a first map
used to "iterate" over all my input values. Then I use a second map to create a series of individual maps that looks like that:
({"a" "id-2"} {"b" "id-2"} {"c" "id-2"} {"a" "id-1"} {"b" "id-1"} {"c" "id-1"})
To get to that map, I create an intermediary array using into [] (repeat ..)
to feed to the map along with the array of values.
Then I merge them together to get my expected value.
Two issues here:
The current end result is not yet perfect since I am getting this:
{"a" (\i \d - \1 \i \d - \2), "b" (\i \d - \1 \i \d - \2), "c" (\i \d - \1 \i \d - \2)}
Upvotes: 1
Views: 715
Reputation: 26436
Using map destructuring:
(apply merge-with into (for [[k {vs "values"}] input, v vs] {v [k]}))
Clearer
(apply merge-with into
(for [[k m] input
v (get m "values")]
{v [k]}))
Upvotes: 8
Reputation: 101032
Given this input:
(def input {"id-1" {"values" ["a" "b" "c"]}, "id-2" {"values" ["a" "b" "c"]}})
it's easier to do:
(defn extract [key values]
(for [v (get values "values")] {v [key]}))
(->> input
(mapcat (partial apply extract))
(apply merge-with concat))
or, without an additional function:
(->> (for [[k vs] input]
(for [v (get vs "values")] {v [k]}))
(flatten)
(apply merge-with concat))
which works the way you intended.
The trick is to wrap key
in a vector in the extract
function so merge-with concat
works without concatenating the strings.
Upvotes: 2