Merge 0ddebad851 into 9a615ff22c
This commit is contained in:
commit
bea6b59724
5 changed files with 80 additions and 9 deletions
|
|
@ -7,8 +7,7 @@ lein do clean, test
|
||||||
# Running ClojureScript tests
|
# Running ClojureScript tests
|
||||||
|
|
||||||
```
|
```
|
||||||
lein javac
|
lein do clean, javac, test-cljs
|
||||||
lein doo node test-build once
|
|
||||||
```
|
```
|
||||||
|
|
||||||
# Running benchmarks
|
# Running benchmarks
|
||||||
|
|
|
||||||
|
|
@ -40,4 +40,5 @@
|
||||||
[["clojars" {:url "https://repo.clojars.org"
|
[["clojars" {:url "https://repo.clojars.org"
|
||||||
:sign-releases false}]]
|
:sign-releases false}]]
|
||||||
|
|
||||||
:aliases {"deploy" ["do" "clean," "deploy" "clojars"]})
|
:aliases {"deploy" ["do" "clean," "deploy" "clojars"]
|
||||||
|
"test-cljs" ["do" "doo" "node" "test-build" "once"]})
|
||||||
|
|
|
||||||
|
|
@ -507,6 +507,11 @@
|
||||||
(defmacro end-fn [& args]
|
(defmacro end-fn [& args]
|
||||||
`(n/->SrangeEndFunction (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))))
|
||||||
|
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -800,7 +805,14 @@
|
||||||
|
|
||||||
|
|
||||||
(defnav
|
(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
|
continuous-subseqs
|
||||||
[pred]
|
[pred]
|
||||||
(select* [this structure next-fn]
|
(select* [this structure next-fn]
|
||||||
|
|
|
||||||
|
|
@ -570,8 +570,38 @@
|
||||||
res
|
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]
|
(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]
|
(defn matching-ranges [aseq p]
|
||||||
(first
|
(first
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
select-any selected-any? collected? traverse
|
select-any selected-any? collected? traverse
|
||||||
multi-transform path dynamicnav recursive-path
|
multi-transform path dynamicnav recursive-path
|
||||||
defdynamicnav traverse-all satisfies-protpath? end-fn
|
defdynamicnav traverse-all satisfies-protpath? end-fn
|
||||||
vtransform]]))
|
subseq-pred-fn vtransform]]))
|
||||||
(:use
|
(:use
|
||||||
#?(:clj [clojure.test :only [deftest is]])
|
#?(:clj [clojure.test :only [deftest is]])
|
||||||
#?(:clj [clojure.test.check.clojure-test :only [defspec]])
|
#?(:clj [clojure.test.check.clojure-test :only [defspec]])
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
select-any selected-any? collected? traverse
|
select-any selected-any? collected? traverse
|
||||||
multi-transform path dynamicnav recursive-path
|
multi-transform path dynamicnav recursive-path
|
||||||
defdynamicnav traverse-all satisfies-protpath? end-fn
|
defdynamicnav traverse-all satisfies-protpath? end-fn
|
||||||
vtransform]]))
|
subseq-pred-fn vtransform]]))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -949,6 +949,23 @@
|
||||||
(= (setval (s/continuous-subseqs pred) nil aseq)
|
(= (setval (s/continuous-subseqs pred) nil aseq)
|
||||||
(filter (complement pred) 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
|
(deftest continuous-subseqs-test
|
||||||
(is (= [1 "ab" 2 3 "c" 4 "def"]
|
(is (= [1 "ab" 2 3 "c" 4 "def"]
|
||||||
|
|
@ -960,7 +977,19 @@
|
||||||
(is (= [[] [2] [4 6]]
|
(is (= [[] [2] [4 6]]
|
||||||
(select
|
(select
|
||||||
[(s/continuous-subseqs number?) (s/filterer even?)]
|
[(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])))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1598,7 +1627,7 @@
|
||||||
(s/comp-paths
|
(s/comp-paths
|
||||||
(s/srange-dynamic
|
(s/srange-dynamic
|
||||||
(fn [aseq] (long (/ (count aseq) 2)))
|
(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
|
s/FIRST
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue