In Clojure I want to find the result of multiple reductions while only consuming the sequence once. In Java I would do something like the following:
double min = Double.MIN_VALUE; double max = Double.MAX_VALUE; for (Item item : items) { double price = item.getPrice(); if (price > min) { min = price; } if (price < max) { max = price; } } In Clojure I could do much the same thing by using loop and recur, but it's not very composable - I'd like to do something that lets you add in other aggregation functions as needed.
I've written the following function to do this:
(defn reduce-multi "Given a sequence of fns and a coll, returns a vector of the result of each fn when reduced over the coll." [fns coll] (let [n (count fns) r (rest coll) initial-v (transient (into [] (repeat n (first coll)))) fns (into [] fns) reduction-fn (fn [v x] (loop [v-current v, i 0] (let [y (nth v-current i) f (nth fns i) v-new (assoc! v-current i (f y x))] (if (= i (- n 1)) v-new (recur v-new (inc i))))))] (persistent! (reduce reduction-fn initial-v r)))) This can be used in the following way:
(reduce-multi [max min] [4 3 6 7 0 1 8 2 5 9]) => [9 0] I appreciate that it's not implemented in the most idiomatic way, but the main problem is that it's about 10x as slow as doing the reductions one at at time. This might be useful for lots performing lots of reductions where the seq is doing heavy IO, but surely this could be better.
Is there something in an existing Clojure library that would do what I want? If not, where am I going wrong in my function?
juxtat github.com/cgrand/xformsjuxtseems perfect ... but not required, right? My understanding is that transducers allow a series of separatereducecalls to be made without intermediate sequences being created, which is what I take to the goal to be here.