Skip to content

Instantly share code, notes, and snippets.

@jgrimes
Last active August 29, 2015 14:16
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jgrimes/c0e048c8a0b8bc9efd7b to your computer and use it in GitHub Desktop.
Save jgrimes/c0e048c8a0b8bc9efd7b to your computer and use it in GitHub Desktop.
reducing multiple functions
lambda.match> (time (sidelong-count-and-sum (range 100000000)))
"Elapsed time: 89361.517429 msecs"
[100000000 4999999950000000]
lambda.match> (time (reduce #((juxt
(partial (fn [x y] (+ x 1)) (first %)) ; count
(partial + (second %))) ; sum
%2)
[1 0]
(range 1 100000000)))
"Elapsed time: 51670.058838 msecs"
[100000000 4999999950000000]
; the macro is faster than the function below since it
; creates the juxted function statically
(defmacro reduce-multi [fns init args]
(let [acc (gensym)
n (gensym)]
`(reduce (fn [~acc ~n]
[~@(map-indexed (fn [arg# f#] `(~f# (nth ~acc ~arg#) ~n)) fns)])
~init
~args)))
(defn reduce-multi [fns init args]
(reduce (fn [acc n]
((apply juxt
(map-indexed #(partial %2 (nth acc %)) fns))
n))
init
args))
@alandipert
Copy link

Reducer version, theoretically data-parallel via fork/join. Uses a map instead of tuple to simplify merging and avoid accidental seq. A vector would work too, it's more a matter of taste considering both types can be reducer'd.

(require '[clojure.core.reducers :as r])

(defn count-sum
  ([] {:count 0 :sum 0})
  ([{:keys [count sum]} n]
   {:count (inc count)
    :sum   (+ sum n)}))

(defn merge-counts-sums
  ([] {:count 0 :sum 0})
  ([& counts-sums]
   (reduce merge-with + counts-sums)))

(time (r/fold merge-counts-sums count-sum (range 100000000)))

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