Skip to content

Commit 6191b5b

Browse files
committed
#236 - Generalize continuous-subseqs
Adding new subseq-pred-fn macro to create the new form of predicate function (taking the previous and current item), to preserve backward compatibility (still allowing predicate functions that only take the current item) Adding SubseqsDynamicPredFn, which works the same as SrangeEndFn, to support backward compatibility Adding wrapper to take a predicate on [prev current] and turn it into a predicate also taking the current index as the first param Creating transducer to combine this with the user-supplied predicate function Adding tests for select and transform WORK IN PROGRESS TODO: figure out how to make predicate function handle an open-ended subsequence (ex: end marker not yet seen)
1 parent 40add56 commit 6191b5b

File tree

3 files changed

+53
-2
lines changed

3 files changed

+53
-2
lines changed

src/clj/com/rpl/specter.cljc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,9 @@
471471
(defmacro end-fn [& args]
472472
`(n/->SrangeEndFunction (fn ~@args)))
473473

474+
(defmacro subseq-pred-fn [& args]
475+
`(i/->SubseqsDynamicPredFn (i/wrap-pred-with-index (fn ~@args))))
476+
474477
))
475478

476479

src/clj/com/rpl/specter/impl.cljc

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -560,8 +560,37 @@
560560
res
561561
))))
562562

563+
(defn wrap-pred-with-index [pred]
564+
(fn [i elem prev]
565+
[(pred elem (first prev)), i]))
566+
567+
;; adapted from clojure.core$keep_indexed
568+
(defn- subseq-pred-fn-transducer
569+
([pred-fn]
570+
(fn [rf]
571+
(let [last-val (volatile! nil) idx (volatile! -1)]
572+
(fn
573+
([] (rf)) ;; init arity
574+
([result] (rf result)) ;; completion arity
575+
([result input] ;; reduction arity
576+
(let [last @last-val
577+
i (vswap! idx inc)
578+
curr ((:pred-fn pred-fn) i input last)]
579+
(vreset! last-val curr)
580+
(if (nil? curr)
581+
result
582+
(rf result curr)))))))))
583+
584+
;; see com.rpl.specter.navs.SrangeEndFunction
585+
(defrecord SubseqsDynamicPredFn [pred-fn])
586+
563587
(defn- matching-indices [aseq p]
564-
(keep-indexed (fn [i e] (if (p e) i)) aseq))
588+
(if (instance? SubseqsDynamicPredFn p)
589+
;; use new subseq predicate form (taking current and previous vals)
590+
(let [index-results (into [] (subseq-pred-fn-transducer p) aseq)]
591+
(map last (filter (comp true? first) index-results)))
592+
;; else use the previous 1-arity predicate
593+
(keep-indexed (fn [i e] (if (p e) i)) aseq)))
565594

566595
(defn matching-ranges [aseq p]
567596
(first

test/com/rpl/specter/core_test.cljc

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -960,7 +960,26 @@
960960
(is (= [[] [2] [4 6]]
961961
(select
962962
[(s/continuous-subseqs number?) (s/filterer even?)]
963-
[1 "a" "b" 2 3 "c" 4 5 6 "d" "e" "f"]))))
963+
[1 "a" "b" 2 3 "c" 4 5 6 "d" "e" "f"])))
964+
(defn- make-bounds-pred-fn [start end]
965+
(s/subseq-pred-fn [elem prev]
966+
(cond
967+
(identical? start elem) start
968+
(identical? end elem) end
969+
(identical? end prev) false
970+
:else (or (identical? start prev) prev)
971+
)))
972+
(is (= [[1 2 3] [8 9]]
973+
(select
974+
[(s/continuous-subseqs (make-bounds-pred-fn :START :END))]
975+
[:START 1 2 3 :END 5 6 7 :START 8 9 :END])))
976+
977+
(is (= [1 2 3 :START-SUM 15 :END-SUM 7 8 9 :START-SUM 21 :END-SUM 12 :START-SUM 13 14]
978+
(transform
979+
(s/continuous-subseqs (make-bounds-pred-fn :START-SUM :END-SUM))
980+
(fn [vals] [(apply + vals)])
981+
[1 2 3 :START-SUM 4 5 6 :END-SUM 7 8 9 :START-SUM 10 11 :END-SUM 12 :START-SUM 13 14])))
982+
)
964983

965984

966985

0 commit comments

Comments
 (0)