Skip to content

Instantly share code, notes, and snippets.

@fxposter
Last active October 7, 2015 03:07
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save fxposter/fb6257f50aa8518d2557 to your computer and use it in GitHub Desktop.
Save fxposter/fb6257f50aa8518d2557 to your computer and use it in GitHub Desktop.
group-by as a transducer
(defn group-by [f]
(fn [rf]
(let [groupped-value (volatile! (transient {}))]
(fn
([] (rf))
([result]
(rf (rf result (persistent! @groupped-value))))
([result input]
(let [key (f input)]
(vswap! groupped-value assoc! key (conj (get @groupped-value key []) input))
result))))))
(def coll (range 1 10))
(def xform (comp (map inc) (filter #(< % 7)) (group-by #(rem % 2)) (mapcat seq)))
(transduce xform conj [] coll)
=> [[0 [2 4 6]] [1 [3 5]]]
var groupBy = function() {
var GroupBy = function(f, rf) {
this.f = f;
this.rf = rf;
this.grouppedValue = {};
};
GroupBy.prototype.init = function() {
return this.rf.init();
};
GroupBy.prototype.result = function(result) {
return this.rf.result(this.rf.step(result, this.grouppedValue));
};
GroupBy.prototype.step = function(result, input) {
var key = this.f(input);
this.grouppedValue[key] = this.grouppedValue[key] || [];
this.grouppedValue[key].push(input);
return result;
};
return function(f) {
return function(rf) {
return new GroupBy(f, rf);
};
};
}();
var t = require ('transducers-js');
var comp = t.comp, map = t.map, filter = t.filter, mapcat = t.mapcat, transduce = t.transduce;
var append = function(accumulator, element) {
accumulator.push(element);
return accumulator;
};
var xform = comp(map(function(x) { return x + 1; }), filter(function(x) { return x < 7; }), groupBy(function(x) { return x % 2; }), mapcat(function(x) { return x; }));
transduce(xform, append, [], [1, 2, 3, 4, 5, 6, 7, 8, 9]);
=> [ [ '0', [ 2, 4, 6 ] ], [ '1', [ 3, 5 ] ] ]
@jeroenvandijk
Copy link

Hi Pavel,

Thanks for this example! I've found it useful while porting some Incanter operations to transducers. One question though, on line 7 you call (rf (rf ...)). Was this necessary? I found that one rf was enough, see my fork

Cheers,
Jeroen

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment