Last active
February 5, 2016 16:13
-
-
Save favila/9ddda543a3f81fda237d to your computer and use it in GitHub Desktop.
grouper-by function: a reduction function compatible with `transduce` which performs an independent stepwise reduction on each group: `group-by` without the intermediate group collections!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defn grouper-by | |
"Return a reducing function which reduces items in groups (determined by | |
result of `(keyfn item)`) independently using optional transducer | |
`group-xform` and reduction function `group-rf` (which should have 3 arities). | |
The supplied reducing and transducing functions may be stateful: their state | |
will be isolated to a particular group. | |
The returned reducing function should be run with `transduce` | |
or `finalizing-reduce` (not `reduce`, which does not use the \"finalize\" | |
arity). It will return a map keyed by `(keyfn item)` whose values are same as | |
`(transduce group-xform group-rf ITEMS-IN-GROUP)`. | |
Example use: | |
(transduce identity | |
(grouper-by first (comp (map second) (take 2)) into-set) | |
[[:a 1] [:b 1] [:c 1] [:a 2] [:b 2] [:a 3] [:b 3] [:d 1]]) | |
;=> {:a #{1 2}, :b #{1 2}, :c #{1}, :d #{1}}" | |
([keyfn group-rf] | |
(grouper-by keyfn identity group-rf)) | |
([keyfn group-xform group-rf] | |
(fn | |
([] (transient {})) | |
([groups] (->> (persistent! groups) | |
(reduce-kv | |
(fn [acc k a] | |
(let [grf (aget a 0) | |
gr (aget a 1)] | |
(assoc! acc k (grf (unreduced gr))))) | |
(transient {})) | |
(persistent!))) | |
([groups x] | |
(let [k (keyfn x)] | |
(if-some [gs (get groups k)] | |
(let [gr (aget gs 1)] | |
(when-not (reduced? gr) | |
(aset gs 1 ((aget gs 0) gr x))) | |
groups) | |
(let [grf (group-xform group-rf) | |
gr (group-rf)] | |
(assoc! groups k (doto (object-array 2) | |
(aset 0 grf) | |
(aset 1 (grf gr x))))))))))) | |
(defn into-set | |
([] (transient #{})) | |
([r] (persistent! r)) | |
([r x] (conj! r x))) | |
(defn into-map | |
([] (transient {})) | |
([r] (persistent! r)) | |
([r [k v]] (assoc! r k v))) | |
(defn finalizing-reduce | |
"A reduce which obeys the same 3-arity reduction function contract as | |
`transduce`: if `init` is not supplied, will call `(f)` for initial value; | |
and will call `(f result-of-reduction)` to finalize the reduction. | |
Same as `(transduce identity f coll)`." | |
([f coll] (finalizing-reduce f (f) coll)) | |
([f init coll] | |
(f (reduce f init coll)))) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment