Reducing/Merging a sequence of maps into a single map

I’m trying to process a nested map. The input looks like this:

(def foo 
{1 [{:id 1, :type "Foo"} {:id 1, :Color "Red"} {:id 1, :Style "Modern"} {:id 1, :Weight "1.0"} {:id 1, :Family "F12"}]
 2 [{:id 2, :type "Foo"} {:id 2, :Color "Black"} {:id 2, :Style "Classic"} {:id 2, :Weight "1.5"} {:id 2, :Family "F12"}]})

The output should merge the maps in the values to a single map:

{
1 {:id 1, :type "Foo", :Color "Red", :Style "Modern", :Weight "1.0", :Family "F12"}
2 {:id 2, :type "Foo", :Color "Black", :Style "Classic", :Weight "1.5", :Family "F12"}} 

So far my approach is to -

(defn f [m1 m2] (merge m1 m2))
(map #(assoc {} (key %) (reduce f (val %))) foo)

This is not exactly right, but more importantly, I feel this is needlessly convoluted, reached at with experimentation on the REPL.

What would be the idiomatic way to reduce the all the value maps into a single map?

Not sure if you actually meant for the for the :id values in the result to be converted to a string. If not, I would probably do this if I was playing with data at the repl:

(->> foo
     (map (fn [[k v]] [k (apply merge v)]))
     (into {}))

Just for completeness sake:

(->> foo
   (map (fn [[k v]] [k (apply merge v)]))
   (map (fn [[k v]]
          [k (assoc v :id (str (:id v)))]))
     (into {}))

Or maybe like this if you prefer to skip the second map:

   (->> foo
      (map (fn [[k v]]
             [k (-> (apply merge v)
                   ((fn[{:keys [id] :as m}]
                      (assoc m :id (str id)))))]))
      (into {}))

I’d probably do something like this:

(reduce (fn [m [k v]] (assoc m k (apply merge v))) {} foo)
3 Likes

The :id values are supposed to be integer all-through, I’ve updated my question.