Created
January 29, 2023 23:19
-
-
Save Chouser/b1a697e0e2e7e887187772b75a28b429 to your computer and use it in GitHub Desktop.
A handful of implementations of "grep -C"
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; 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