2013-03-22 97 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