我有一组地图
(def a '({:id 9345 :value 3 :type "orange"}
{:id 2945 :value 2 :type "orange"}
{:id 145 :value 3 :type "orange"}
{:id 2745 :value 6 :type "apple"}
{:id 2345 :value 6 :type "apple"}))
我想先按值分组,然后按类型分组。
我的输出应该如下:
{
:orange [{
:value 3,
:id [9345, 145]
}, {
:value 2,
:id [2935]
}],
:apple [{
:value 6,
:id [2745, 2345]
}]
}
我如何在Clojure中做到这一点?感谢您的回答。
谢谢!
修改:
这是我到目前为止所做的:
(defn by-type-key [data]
(group-by #(get % "type") data))
(reduce-kv
(fn [m k v] (assoc m k (reduce-kv
(fn [sm sk sv] (assoc sm sk (into [] (map #(:id %) sv))))
{}
(group-by :value (map #(dissoc % :type) v)))))
{}
(by-type-key a))
输出:
=> {"orange" {3 [9345 145], 2 [2945]}, "apple" {6 [2745 2345], 3 [125]}}
我无法弄清楚如何继续......
答案 0 :(得分:2)
您的要求有点不一致(或者说不规则) - 您在结果中使用:type
值作为关键字,但其余的关键字都是通过的。也许你需要做些什么才能满足一些外部格式 - 否则你需要使用与:type
相同的方法,或者在结果中添加新的关键字,如:group
或:rows
并保持原始关键字的完整性。我将暂时采用前一种方法(但请参见下文,我将根据您的需要得到形状),因此最终的数据形状就像
{:orange
{:3 [9345 145],
:2 [2945]},
:apple
{:6 [2745 2345]}
}
到达那里的方法不止一种,这里有一个要点:
(group-by (juxt :type :value) a)
结果:
{["orange" 3] [{:id 9345, :value 3, :type "orange"} {:id 145, :value 3, :type "orange"}],
["orange" 2] [{:id 2945, :value 2, :type "orange"}],
["apple" 6] [{:id 2745, :value 6, :type "apple"} {:id 2345, :value 6, :type "apple"}]}
现在,您的集合中的所有行都按您需要的键分组。从这里,你可以去获得你想要的形状,比如说你可以做到上面的形状
(reduce
(fn [m [k v]]
(let [ks (map (comp keyword str) k)]
(assoc-in m ks
(map :id v))))
{}
(group-by (juxt :type :value) a))
基本思路是按键序列(以及group-by
和juxt
执行的操作)对行进行分组,然后合并reduce
和{{1 }或assoc-in
将结果击败到位。
要准确获得您描述的形状:
update-in
它有点吵,可能更难看到树木的森林 - 这就是为什么我简化形状,突出主要想法。你的形状越规则,你的功能越短越规则 - 所以如果你能控制它,试着让它更简单。
答案 1 :(得分:1)
您可能希望使用内置函数{{1}}。见http://clojuredocs.org/clojure.core/group-by
答案 2 :(得分:1)
我会分两个阶段进行转换(使用reduce):
以下代码解决了您的问题:
(def a '({:id 9345 :value 3 :type "orange"}
{:id 2945 :value 2 :type "orange"}
{:id 145 :value 3 :type "orange"}
{:id 2745 :value 6 :type "apple"}
{:id 2345 :value 6 :type "apple"}))
(defn standardise [m]
(->> m
;; first stage
(reduce (fn [out {:keys [type value id]}]
(update-in out [type value] (fnil #(conj % id) [])))
{})
;; second stage
(reduce-kv (fn [out k v]
(assoc out (keyword k)
(reduce-kv (fn [out value id]
(conj out {:value value
:id id}))
[]
v)))
{})))
(standardise a)
;; => {:orange [{:value 3, :id [9345 145]}
;; {:value 2, :id [2945]}],
;; :apple [{:value 6, :id [2745 2345]}]}
第一阶段的输出是:
(reduce (fn [out {:keys [type value id]}]
(update-in out [type value] (fnil #(conj % id) [])))
{}
a)
;;=> {"orange" {3 [9345 145], 2 [2945]}, "apple" {6 [2745 2345]}}