假设我有一个集合,比如:
(def xs
[{:name "Apple" :type "Fruit is a type"}
{:name "Tomato" :type "Vegetable are food"}
{:name "Pear" :type "the type can also be Fruit"}
{:name "Steak" :type "eat less Meat"}])
我想按集合进行过滤和分组,形成这样的内容:
{:Fruit [{:name "Apple" :type "Fruit is a type"} {:name "Pear" :type "the type can also be Fruit"}] :Vegetable [{:name "Tomato" :type "Vegetable are food"}]
我目前只是过滤结果,但似乎找不到一个好的分组方法。到目前为止,我拥有的是:
(defn filter-response [x query]
(filter #(s/includes? (:type %) query) x))
(defn group-by-types [queries]
(map #(filter-response xs %) queries))
(group-by-types ["Fruit" "Vegetable"])
我怎样才能做到这一点?
更新的答案
您可以使用列表理解来检查集合中每个项目的每个模式。
(defn- all-occurrences [xs patterns]
(for [x xs
pattern patterns
:when (clojure.string/includes? (:type x) pattern)]
[(keyword pattern) x]))
或者使用filter-response
函数:
(defn- all-occurrences [xs patterns]
(for [pattern patterns
x (filter-response xs pattern)]
[(keyword pattern) x]))
然后使用reduce with update将出现的列表合并到一个单独的地图中:
(defn group-by-patterns [xs patterns]
(reduce (fn [m [pattern text]] (update m pattern conj text))
{}
(all-occurrences xs patterns)))
用新的输入调用它:
(def xs
[{:name "Apple" :type "Fruit is a type"}
{:name "Tomato" :type "Vegetable are food"}
{:name "Pear" :type "the type can also be Fruit"}
{:name "Steak" :type "eat less Meat"}])
(group-by-patterns xs ["Fruit" "Vegetable"])
=> {:Fruit ({:name "Pear", :type "the type can also be Fruit"} {:name "Apple", :type "Fruit is a type"}),
:Vegetable ({:name "Tomato", :type "Vegetable are food"})}
原始答案
首先,您可以使用分组依据对指定键下的值进行分组:
(def xs
[{:name "Apple" :type "Fruit"}
{:name "Tomato" :type "Vegetable"}
{:name "Pear" :type "Fruit"}
{:name "Steak" :type "Meat"}])
erdos=> (group-by :type xs)
{"Fruit" [{:name "Apple", :type "Fruit"} {:name "Pear", :type "Fruit"}],
"Vegetable" [{:name "Tomato", :type "Vegetable"}],
"Meat" [{:name "Steak", :type "Meat"}]}
然后使用选择键过滤密钥:
erdos=> (select-keys (group-by :type xs) ["Fruit" "Vegetable"])
{"Fruit" [{:name "Apple", :type "Fruit"} {:name "Pear", :type "Fruit"}],
"Vegetable" [{:name "Tomato", :type "Vegetable"}]}
如果你需要关键字密钥,你需要一个额外的映射步骤:
erdos=> (into {}
(for [[k v] (select-keys (group-by :type xs) ["Fruit" "Vegetable"])]
[(keyword k) v]))
{:Fruit [{:name "Apple", :type "Fruit"} {:name "Pear", :type "Fruit"}],
:Vegetable [{:name "Tomato", :type "Vegetable"}]}