Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#236 - Generalize continuous-subseqs #294

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions DEVELOPER.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@ lein do clean, test
# Running ClojureScript tests

```
lein javac
lein doo node test-build once
lein do clean, javac, test-cljs
```
3 changes: 2 additions & 1 deletion project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,5 @@
[["clojars" {:url "https://repo.clojars.org"
:sign-releases false}]]

:aliases {"deploy" ["do" "clean," "deploy" "clojars"]})
:aliases {"deploy" ["do" "clean," "deploy" "clojars"]
"test-cljs" ["do" "doo" "node" "test-build" "once"]})
14 changes: 13 additions & 1 deletion src/clj/com/rpl/specter.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,11 @@
(defmacro end-fn [& args]
`(n/->SrangeEndFunction (fn ~@args)))

(defmacro subseq-pred-fn
"Used in conjunction with `continuous-subseqs`. See [[continuous-subseqs]]."
[get-truthy-fn & args]
`(i/->SubseqsDynamicPredFn ~get-truthy-fn (i/wrap-pred-with-index (fn ~@args))))

))


Expand Down Expand Up @@ -800,7 +805,14 @@


(defnav
^{:doc "Navigates to every continuous subsequence of elements matching `pred`"}
^{:doc "Navigates to every continuous subsequence of elements matching `pred`. `pred` can be specified one of two
forms. If a regular function (e.g. defined with `fn`), it takes in only the current element as input. If
defined using the special `subseq-pred-fn` macro, it takes in a `get-truthy-fn` as its first parameter,
followed by arguments to a predicate function [`elem` `prev`], followed by the predicate function body. The
`elem` argument to the predicate function is the current element, and the `pred` argument is the value
returned by your predicate on the previous element, so it can be in any structure you choose. `get-truthy-fn`
is a function that should return true from your predicate's return structure if that element should be
included in a subsequence."}
continuous-subseqs
[pred]
(select* [this structure next-fn]
Expand Down
32 changes: 31 additions & 1 deletion src/clj/com/rpl/specter/impl.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -546,8 +546,38 @@
res
))))

(defn wrap-pred-with-index [pred]
(fn [i elem prev]
[(pred elem (first prev)), i]))

;; adapted from clojure.core$keep_indexed
(defn- subseq-pred-fn-transducer
([pred-fn]
(fn [rf]
(let [last-val (volatile! nil) idx (volatile! -1)]
(fn
([] (rf)) ;; init arity
([result] (rf result)) ;; completion arity
([result input] ;; reduction arity
(let [last @last-val
i (vswap! idx inc)
curr ((:pred-fn pred-fn) i input last)]
(vreset! last-val curr)
(if (nil? curr)
result
(rf result curr)))))))))

;; see com.rpl.specter.navs.SrangeEndFunction
(defrecord SubseqsDynamicPredFn [get-truthy-fn pred-fn])

(defn- matching-indices [aseq p]
(keep-indexed (fn [i e] (if (p e) i)) aseq))
(if (instance? SubseqsDynamicPredFn p)
;; use new subseq predicate form (taking current and previous vals)
(let [index-results (into [] (subseq-pred-fn-transducer p) aseq)]
;; apply the get-truthy-fn to extract the truthy (i.e. include) result
(map last (filter (comp true? (:get-truthy-fn p) first) index-results)))
;; else use the previous 1-arity predicate
(keep-indexed (fn [i e] (if (p e) i)) aseq)))

(defn matching-ranges [aseq p]
(first
Expand Down
37 changes: 33 additions & 4 deletions test/com/rpl/specter/core_test.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
select-any selected-any? collected? traverse
multi-transform path dynamicnav recursive-path
defdynamicnav traverse-all satisfies-protpath? end-fn
vtransform]]))
subseq-pred-fn vtransform]]))
(:use
#?(:clj [clojure.test :only [deftest is]])
#?(:clj [clojure.test.check.clojure-test :only [defspec]])
Expand All @@ -23,7 +23,7 @@
select-any selected-any? collected? traverse
multi-transform path dynamicnav recursive-path
defdynamicnav traverse-all satisfies-protpath? end-fn
vtransform]]))
subseq-pred-fn vtransform]]))



Expand Down Expand Up @@ -949,6 +949,23 @@
(= (setval (s/continuous-subseqs pred) nil aseq)
(filter (complement pred) aseq))))

(defn- make-bounds-pred-fn-vecs [start end]
(s/subseq-pred-fn first [elem prev]
(let [[included last] prev]
(cond
(= start elem) [false start]
(= end elem) [false end]
(= end last) [false elem]
:else [(or (= start last) included) elem]))))

(defn- make-bounds-pred-fn-maps [start end]
(s/subseq-pred-fn :include [elem prev]
(let [{include :include last :last} prev]
(cond
(= start elem) {:include false :last start}
(= end elem) {:include false :last end}
(= end last) {:include false :last elem}
:else {:include (or (= start last) include) :last elem}))))

(deftest continuous-subseqs-test
(is (= [1 "ab" 2 3 "c" 4 "def"]
Expand All @@ -960,7 +977,19 @@
(is (= [[] [2] [4 6]]
(select
[(s/continuous-subseqs number?) (s/filterer even?)]
[1 "a" "b" 2 3 "c" 4 5 6 "d" "e" "f"]))))
[1 "a" "b" 2 3 "c" 4 5 6 "d" "e" "f"])))
(is (= [[1 2 3] [8 9]]
(select
[(s/continuous-subseqs (make-bounds-pred-fn-vecs :START :END))]
[:START 1 2 3 :END 5 6 7 :START 8 9 :END])))

(is (= [1 2 3 :START-SUM 15 :END-SUM 7 8 9 :START-SUM 21 :END-SUM 12 :START-SUM 27 :END-SUM]
(transform
(s/continuous-subseqs (make-bounds-pred-fn-maps :START-SUM :END-SUM))
(fn [vals] [(apply + vals)])
[1 2 3 :START-SUM 4 5 6 :END-SUM 7 8 9 :START-SUM 10 11 :END-SUM 12 :START-SUM 13 14 :END-SUM])))
)




Expand Down Expand Up @@ -1589,7 +1618,7 @@
(s/comp-paths
(s/srange-dynamic
(fn [aseq] (long (/ (count aseq) 2)))
(end-fn [aseq s] (if (empty? aseq) 0 (inc s))))
(s/end-fn [aseq s] (if (empty? aseq) 0 (inc s))))
s/FIRST
))

Expand Down