Skip to content

Instantly share code, notes, and snippets.

@Chouser
Created January 29, 2023 23:19
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 Chouser/b1a697e0e2e7e887187772b75a28b429 to your computer and use it in GitHub Desktop.
Save Chouser/b1a697e0e2e7e887187772b75a28b429 to your computer and use it in GitHub Desktop.
A handful of implementations of "grep -C"
;; primitive lazy-seq
(defn filter-with-context-ls [pred n coll]
(let [step (fn step [buffer suffix coll]
(lazy-seq
(when-let [[v & more] (seq coll)]
(if (pred v)
(concat (take-last n buffer) [v] (step [] n more))
(if (pos? suffix)
(cons v (step [] (dec suffix) more))
(step (conj buffer v) 0 more))))))]
(step [] 0 coll)))
(filter-with-context-ls #(or (= 1 %) (= 4 %) (= 11 %)) 2 (range 20))
;; loop/recur
(defn filter-with-context-lr [pred n coll]
(loop [out [], buffer [], suffix 0, coll coll]
(if-let [[v & more] (seq coll)]
(if (pred v)
(recur (-> out
(into (take-last n buffer))
(conj v))
[] n more)
(if (pos? suffix)
(recur (conj out v) [] (dec suffix) more)
(recur out (conj buffer v) 0 more)))
out)))
(filter-with-context-lr #(or (= 1 %) (= 4 %) (= 11 %)) 2 (range 20))
;; ezducer (one of the variants)
(defn filter-with-context-ez [pred n]
(let [*buffer (volatile! [])
*suffix (volatile! 0)]
(ezducer4c
(fn [{:keys [step2]}]
{:step1 (fn [v]
(if (pred v)
(do
(run! step2 (take-last n @*buffer))
(step2 v)
(vreset! *buffer [])
(vreset! *suffix n))
(if (pos? @*suffix)
(do
(step2 v)
(vswap! *suffix dec))
(vswap! *buffer conj v))))}))))
(into [] (filter-with-context-ez #(or (= 1 %) (= 4 %) (= 11 %)) 2)
(range 20))
;; standard transducer
(defn filter-with-context-st [pred n]
(fn transducer [r]
(let [*buffer (volatile! [])
*suffix (volatile! 0)]
(fn
([] (r))
([a v]
(if (pred v)
(loop [a a
buf (take-last n @*buffer)]
(if (seq buf)
(let [a (r a (first buf))]
(if (reduced? a)
a
(recur a (rest buf))))
(do
(vreset! *buffer [])
(vreset! *suffix n)
(r a v))))
(if (pos? @*suffix)
(do
(vswap! *suffix dec)
(r a v))
(do
(vswap! *buffer conj v)
a))))
([a] (r a))))))
(into [] (filter-with-context-st #(or (= 1 %) (= 4 %) (= 11 %)) 2)
(range 20))
;; high-order lazy seq
(defn filter-with-context-hl [pred n coll]
(let [skipme (reify)
padded (concat (repeat n skipme)
coll
(repeat n skipme))
matches (->> padded
(partition (+ 1 (* 2 n)) 1)
(map #(zipmap [:idx :match :window] %&)
(range)
coll)
(filter #(pred (:match %))))]
(->> matches
(mapcat (fn [prev-m m]
(if-not prev-m
(:window m)
(drop (+ (- (:idx m))
(:idx prev-m)
(* 2 n)
1)
(:window m))))
(cons nil matches))
(remove #(= % skipme)))))
(filter-with-context-hl #(or (= 1 %) (= 4 %) (= 11 %)) 2 (range 20))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment