Skip to content

Instantly share code, notes, and snippets.

@teaforthecat
Last active February 19, 2018 23:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save teaforthecat/179342c515658b4492ab94ff3fad210b to your computer and use it in GitHub Desktop.
Save teaforthecat/179342c515658b4492ab94ff3fad210b to your computer and use it in GitHub Desktop.
fun with accumlating window transducer
(defn accumulate
"If an input satisfies ACC-PRED, accumulate it with ACC-FN (defaults to merge)
All inputs will be passed on normally.
All accumulated inputs will be merged (using ACC-FN) to following inputs until RESET-PRED.
The input that satisfies RESET-PRED will receive the accumulated values and the input following it will receive none.
The default ACC-FN, `merge`, assumes a stream of maps"
([acc-pred reset-pred]
(accumulate acc-pred reset-pred merge))
([acc-pred reset-pred acc-fn]
(accumulate acc-pred reset-pred merge merge))
([acc-pred reset-pred acc-fn disperse-fn]
(fn [xf]
(let [prev (volatile! nil)
reset (volatile! false)]
(fn
;; init
([] (xf))
;; step
([result input]
;; stored from previous run
(if @reset
(do
(vreset! prev nil)
(vreset! reset false)))
(cond
(acc-pred input)
(do
(vswap! prev acc-fn input)
result)
(reset-pred input)
(do
;; close the window
(vreset! reset true)
;; emit the trailer
(xf result (disperse-fn input @prev)))
:default
;; normal input
(xf result (disperse-fn input @prev))))
;; terminate
([result]
(if (and @prev (not @reset))
(xf result (disperse-fn nil @prev)))
(xf result)))))))
(defn assoc-if [m k v]
(if (not-empty v)
(assoc m k v)
m))
(into [] (accumulate :hdr :trl merge #(assoc-if %1 :hdr %2) ) [{:a 1} {:hdr true :b 2} {:c 3} {:trl true :d 4} {:e 5}])
;;=> [{:a 1} {:c 3, :hdr {:hdr true, :b 2}} {:trl true, :d 4, :hdr {:hdr true, :b 2}} {:e 5}]
;; with last element a closing window input
(into [] (accumulate #(not (zero? (:n %))) ;;accumulate :n not zero
#(zero? (:n %)) ;; reset when :n zero
conj ;; create a list of :n's
#(assoc-if %1 :prev %2)) ;; stuff them into the last thing
[{:n 0} {:n 1} {:n 2} {:n 3} {:n 0}])
;;=> [{:n 0} {:n 0, :prev ({:n 3} {:n 2} {:n 1})}]
;; with no closing window input
(into [] (accumulate #(not (zero? (:n %))) ;;accumulate :n not zero
#(zero? (:n %)) ;; reset when :n zero
conj ;; create a list of :n's
#(assoc-if %1 :prev %2)) ;; stuff them into the last thing
[{:n 0} {:n 1} {:n 2} {:n 3}])
;;=> [{:n 0} {:prev ({:n 3} {:n 2} {:n 1})}]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment