2013-03-22 28 views
4

減少我想要聚合大量的數據可能要達到這樣的組用Clojure中

SELECT SUM(`profit`) as `profit`, `month` FROM `t` GROUP BY `month` 

所以,我修改Clojure的組,按功能,像這樣

(defn group-reduce [f red coll] 
    (persistent! 
    (reduce 
    (fn [ret x] 
     (let [k (f x)] 
     (assoc! ret k (red (get ret k) x)))) 
    (transient {}) coll))) 

而這裏的用法:

(group-reduce :month (fn [s x] 
         (if s 
         (assoc s :profit (+ (:profit s) (:profit x))) 
         x)) 
       [{:month 10 :profit 12} 
       {:month 10 :profit 15} 
       {:month 12 :profit 1}]) 

#_=> {10 {:profit 27, :month 10}, 12 {:profit 1, :month 12}} 

它的工作,但也許有另一種方式來做到這一點,使用clojure標準庫?

+1

東西是不完全正確這裏。我預計第10個月的總利潤爲27美元。 – 2013-03-22 14:32:18

+0

對不起,當然是,只是一個錯字。固定。 – h3x3d 2013-03-22 15:59:43

+2

不,我使用它很多,這裏例如https://github.com/cgrand/utils/blob/master/src/net/cgrand/utils.clj#L8 – cgrand 2013-03-26 10:12:38

回答

4

最近的核心是merge-with

(def t [{:month 10 :profit 12} 
     {:month 10 :profit 15} 
     {:month 12 :profit 1}]) 

(apply merge-with + (for [x t] {(:month x) (:profit x)})) 
;=> {12 1, 10 27} 
2

一些例子:

user=> (def groups (group-by :month [{:month 10 :profit 12} 
    #_=>        {:month 10 :profit 15} 
    #_=>        {:month 12 :profit 1}]) 
{10 [{:profit 12, :month 10} {:profit 15, :month 10}], 12 [{:profit 1, :month 12}]} 

user=> (for [[k v] groups] {:month k :sum-profit (apply + (map :profit v))}) 
({:month 10, :sum-profit 27} {:month 12, :sum-profit 1}) 

user=> (into {} (for [[k v] groups] [k (apply + (map :profit v))])) 
{10 27, 12 1} 
+0

這裏的問題是,有很多數據,即使是一個密鑰,所以 - group-by可能會在內存上失敗。 – h3x3d 2013-03-22 16:01:59

+0

如果這是問題,那麼我認爲你的方法是理智的。使用Reducers庫可能值得我們去嘗試一下嗎? – 2013-03-22 16:52:26

+1

@MichielBorkent使用reducer(尤其是文件夾)並不是那麼容易,因爲你不能在文件夾中使用瞬變(我在dev ML上討論過它並提出了一個修正)。所以對於許多工作負載,順序瞬態處理跳動並行持久。 – cgrand 2013-03-26 10:17:04