1

I have a sequence of maps.

;; input
[{:country "MX", :video 12345, :customer "cid1"}
 {:country "US", :video 12345, :customer "cid2"}
 {:country "MX", :video 54321, :customer "cid1"}]

I want to convert it into a multimap. I want to generate.

;; output
{"cid1"
     {:actions
          [{:country "MX", :video 12345, :customer "cid1"}
           {:country "MX", :video 12345, :customer "cid1"}]},
 "cid2" 
     {:actions
          [{:country "US", :video 12345, :customer "cid2"}]}}

I feel like I should be using update-in. Something along the lines of... I just have not worked out exactly what some-fn-here looks like and I figured that others may have the same question.

(defn add-mm-entry
    [m e]
    (update-in m [(:customer e)] some-fn-here))

(def output (reduce add-mm-entry {} input))

Figured I'd throw it out to the community while I work on it. If I'm going down the wrong path here let me know.

2 Answers 2

5

If I understand the intent correctly, you are grouping by :customer and then wrapping the vector of actions into :actions. You can do the grouping with clojure.core/group-by and then map (clojure.core/map) the result:

(def v [{:country "MX", :video 12345, :customer "cid1"}
        {:country "US", :video 12345, :customer "cid2"}
        {:country "MX", :video 54321, :customer "cid1"}])

(->> v
     (group-by :customer)
     (map (fn [[cid xs]] {cid {:actions xs}}))
     (into {}))
Sign up to request clarification or add additional context in comments.

1 Comment

The final output should be a map, so you need to run the result through (into {}).
2

Michael's answer works well. I'm not sure if group-by will work well for my specific case because of the size of the data that I am loading. I have not tested it but I think this approach will lead to less intermediate product.

(def v [{:country "MX", :video 12345, :customer "cid1"}
        {:country "US", :video 12345, :customer "cid2"}
        {:country "MX", :video 54321, :customer "cid1"}])

(defn add-entry
    [m e]
    (let [cust (:customer e)]
        (update-in m [cust :actions] #(conj % e))))

(reduce add-entry {} v)

Still results in full data set being loaded, but it is directly loaded into the target data structure instead of into a vector of maps and then into a multimap. Again, I have not tested to check which one is definitively more performant, but it looks like this one has one less iteration over the data set and avoids creating the unwanted vector of maps that comes out of group-by.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.