简体   繁体   中英

Clojure / Clojurescript: group-by a map on multiple values

Given a data structure, I'd like to re-structure it to be grouped by one of the nested values. These values are vectors, and whenever I encounter more than one value, I'm getting stuck.

Given a vector of maps like this:

(def tools 
 [{:name "A",
   :config
   {:accepts ["id"],
    :classes ["X"]}}
  {:name "B",
   :config
   {:accepts ["id"],
    :classes ["X", "Y"]
    }}])

I can almost get what I want - the values sorted by "classes" as a key, with values repeated if need be - by running group-by :

(group-by #(get-in % [:config :classes]) tools)

But it takes the whole vector in :classes as the key.

 {["X"] [{:name "A", 
          :config {:accepts ["id"], 
                   :classes ["X"]}}], 
  ["X" "Y"] [{:name "B", 
              :config {:accepts ["id"], 
                       :classes ["X" "Y"]}}]}

What I really want is to copy the values once per class, to look like this:

 {"X" [{:name "A"
        :config {:accepts ["id"]
                 :classes ["X"]}}
       {:name "B"
        :config {:accepts ["id"]
                 :classes ["X" "Y"]}}]
  "Y" [{:name "B"
        :config {:accepts ["id"]
                 :classes ["X" "Y"]}}]}

I'm not quite sure how to handle this given that I have multiple values in classes .

Working repl demo: https://repl.it/@YoYehudi/FamiliarDisguisedXiphiasgladius

Here's a way to do it using a nested reduce :

(defn aggregate-classes [m tool]
  (->> (get-in tool [:config :classes])
       (reduce (fn [acc elem]
                 (update acc elem conj tool))
               m)))

(reduce aggregate-classes {} tools)
=>
{"X" ({:name "B", :config {:accepts ["id"], :classes ["X" "Y"]}} {:name "A", :config {:accepts ["id"], :classes ["X"]}}),
 "Y" ({:name "B", :config {:accepts ["id"], :classes ["X" "Y"]}})}
(apply merge-with into {}
       (for [tool tools
             class (get-in tool [:config :classes])]
         {class [tool]}))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM