Tags

, , , , ,

(defmacro multiple-reduce
  [bindings coll]
  `(reduce
     (fn [state# value#]
       (apply
         array-map
         (apply
           concat
           (map
             (fn [[key# default# func#]]
               [key# (func# (get state# key# default#) value#)])
             (partition
               3
               ~bindings)))))
     {}
     ~coll))

Macro for doing multiple parallel aggregations on objects sequence resulting in single aggregate object.

multiple-reduce is defined under clj-common project

Example:

(multiple-reduce
  [
    :inc 0 #(+ %1 (inc %2))
    :dec 0 #(+ %1 (dec %2))]
  '(1 2 3))

will result with

{:inc 9, :dec 3}

Each binding is defined with  keyword that will contain aggregated value after aggregation is finished, initial value and aggregate function ( f(state, value) -> state ). Aggregate function is function of two args, aggregated value ( state ) and increment value ( value ) which with each iteration returns new state.

Example usage from my project

(let [first-location (first locations-seq)
      aggregate (multiple-reduce
                  [
                    :max-longitude (:longitude first-location) (partial max-aggregate :longitude)
                    :min-longitude (:longitude first-location) (partial min-aggregate :latitude)
                    :max-latitude (:latitude first-location) (partial max-aggregate :latitude)
                    :min-latitude (:latitude first-location) (partial min-aggregate :latitude)
                    :distance [0 first-location] distance-aggregate
                    :last-location first-location last-location-aggregate
                    :activity-duration [0 first-location] duration-without-pause]
                    locations-seq)]
  
  ;continue computation on aggregate

  )

Where distance-aggregate is defined as

(defn distance-aggregate [[distance previous-location] location]
  [(+ distance (geo/distance-two-locations previous-location location)) location])
Advertisements