Merge 79f93e57d6 into 9a615ff22c
This commit is contained in:
commit
4af3627b90
5 changed files with 97 additions and 2 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
## 1.1.4
|
## 1.1.4
|
||||||
|
|
||||||
|
* Add SORTED, sorted, and sorted-by navs (thanks @IGJoshua)
|
||||||
* Add arglist metadata to navs (thanks @phronmophobic)
|
* Add arglist metadata to navs (thanks @phronmophobic)
|
||||||
* Improve before-index performance by 150x on lists and 5x on vectors (thanks @jeff303)
|
* Improve before-index performance by 150x on lists and 5x on vectors (thanks @jeff303)
|
||||||
* Bug fix: BEFORE-ELEM, AFTER-ELEM, FIRST, LAST, BEGINNING, and END on subvecs now produce vector type in cljs
|
* Bug fix: BEFORE-ELEM, AFTER-ELEM, FIRST, LAST, BEGINNING, and END on subvecs now produce vector type in cljs
|
||||||
|
|
|
||||||
|
|
@ -1504,3 +1504,61 @@
|
||||||
[& path]
|
[& path]
|
||||||
(map compact* path)
|
(map compact* path)
|
||||||
))
|
))
|
||||||
|
|
||||||
|
(defnav
|
||||||
|
^{:doc "Navigates to a sequence resulting from (sort ...), but is a
|
||||||
|
view to the original structure that can be transformed.
|
||||||
|
|
||||||
|
If the transformed sequence is smaller than the input sequence, values
|
||||||
|
which are included are sorted by the same indices as the input value's
|
||||||
|
index in the input sequence.
|
||||||
|
|
||||||
|
If the transformed sequence is larger than the input sequence, values
|
||||||
|
added to the end of the sequence will be appended to the end of the
|
||||||
|
original sequence."}
|
||||||
|
SORTED
|
||||||
|
[]
|
||||||
|
(select* [this structure next-fn]
|
||||||
|
(n/sorted-select structure identity compare next-fn))
|
||||||
|
(transform* [this structure next-fn]
|
||||||
|
(n/sorted-transform structure identity compare next-fn)))
|
||||||
|
|
||||||
|
(defnav
|
||||||
|
^{:doc "Navigates to a sequence resulting from (sort comparator ...), but
|
||||||
|
is a view to the original structure that can be transformed.
|
||||||
|
|
||||||
|
If the transformed sequence is smaller than the input sequence, values
|
||||||
|
which are included are sorted by the same indices as the input value's
|
||||||
|
index in the input sequence.
|
||||||
|
|
||||||
|
If the transformed sequence is larger than the input sequence, values
|
||||||
|
added to the end of the sequence will be appended to the end of the
|
||||||
|
original sequence."}
|
||||||
|
sorted
|
||||||
|
[comparator]
|
||||||
|
(select* [this structure next-fn]
|
||||||
|
(n/sorted-select structure identity comparator next-fn))
|
||||||
|
(transform* [this structure next-fn]
|
||||||
|
(n/sorted-transform structure identity comparator next-fn)))
|
||||||
|
|
||||||
|
(defdynamicnav sorted-by
|
||||||
|
"Navigates to a sequence sorted by the value stored in the keypath, by the
|
||||||
|
comparator, if one is provided.
|
||||||
|
|
||||||
|
This sequence is a view to the original structure that can be transformed. If
|
||||||
|
the transformed sequence is smaller than the input sequence, values which are
|
||||||
|
included are sorted by the same indices as the input value's index in the
|
||||||
|
input sequence.
|
||||||
|
|
||||||
|
If the transformed sequence is larger than the input sequence, values added to
|
||||||
|
the end of the sequence will be appended to the end of the original sequence.
|
||||||
|
|
||||||
|
Value collection (e.g. collect, collect-one) may not be used in the keypath."
|
||||||
|
([keypath] (sorted-by keypath compare))
|
||||||
|
([keypath comparator]
|
||||||
|
(late-bound-nav [late (late-path keypath)
|
||||||
|
late-fn comparator]
|
||||||
|
(select* [this structure next-fn]
|
||||||
|
(n/sorted-select structure #(compiled-select-one! late %) late-fn next-fn))
|
||||||
|
(transform* [this structure next-fn]
|
||||||
|
(n/sorted-transform structure #(compiled-select-one! late %) late-fn next-fn)))))
|
||||||
|
|
|
||||||
|
|
@ -570,6 +570,18 @@
|
||||||
res
|
res
|
||||||
))))
|
))))
|
||||||
|
|
||||||
|
(defn sorted-transform*
|
||||||
|
[structure keyfn comparator next-fn]
|
||||||
|
(let [sorted (sort-by (comp keyfn second) comparator (map-indexed vector structure))
|
||||||
|
indices (map first sorted)
|
||||||
|
result (next-fn (map second sorted))
|
||||||
|
unsorted (sort-by first compare (map vector indices result))]
|
||||||
|
(if (seq? structure)
|
||||||
|
(doall (map second unsorted))
|
||||||
|
(into (empty structure)
|
||||||
|
(map second)
|
||||||
|
unsorted))))
|
||||||
|
|
||||||
(defn- matching-indices [aseq p]
|
(defn- matching-indices [aseq p]
|
||||||
(keep-indexed (fn [i e] (if (p e) i)) aseq))
|
(keep-indexed (fn [i e] (if (p e) i)) aseq))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -401,6 +401,11 @@
|
||||||
|
|
||||||
(def srange-transform i/srange-transform*)
|
(def srange-transform i/srange-transform*)
|
||||||
|
|
||||||
|
(defn sorted-select
|
||||||
|
[structure keyfn comparator next-fn]
|
||||||
|
(next-fn (sort-by keyfn comparator structure)))
|
||||||
|
|
||||||
|
(def sorted-transform i/sorted-transform*)
|
||||||
|
|
||||||
(defn extract-basic-filter-fn [path]
|
(defn extract-basic-filter-fn [path]
|
||||||
(cond (fn? path)
|
(cond (fn? path)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
(ns com.rpl.specter.core-test
|
(ns com.rpl.specter.core-test
|
||||||
#?(:cljs (:require-macros
|
#?(:cljs (:require-macros
|
||||||
[cljs.test :refer [is deftest]]
|
[cljs.test :refer [is deftest testing]]
|
||||||
[clojure.test.check.clojure-test :refer [defspec]]
|
[clojure.test.check.clojure-test :refer [defspec]]
|
||||||
[com.rpl.specter.cljs-test-helpers :refer [for-all+]]
|
[com.rpl.specter.cljs-test-helpers :refer [for-all+]]
|
||||||
[com.rpl.specter.test-helpers :refer [ic-test]]
|
[com.rpl.specter.test-helpers :refer [ic-test]]
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
defdynamicnav traverse-all satisfies-protpath? end-fn
|
defdynamicnav traverse-all satisfies-protpath? end-fn
|
||||||
vtransform]]))
|
vtransform]]))
|
||||||
(:use
|
(:use
|
||||||
#?(:clj [clojure.test :only [deftest is]])
|
#?(:clj [clojure.test :only [deftest is testing]])
|
||||||
#?(:clj [clojure.test.check.clojure-test :only [defspec]])
|
#?(:clj [clojure.test.check.clojure-test :only [defspec]])
|
||||||
#?(:clj [com.rpl.specter.test-helpers :only [for-all+ ic-test]])
|
#?(:clj [com.rpl.specter.test-helpers :only [for-all+ ic-test]])
|
||||||
#?(:clj [com.rpl.specter
|
#?(:clj [com.rpl.specter
|
||||||
|
|
@ -1711,3 +1711,22 @@
|
||||||
(is (satisfies-protpath? FooPP "a"))
|
(is (satisfies-protpath? FooPP "a"))
|
||||||
(is (not (satisfies-protpath? FooPP 1)))
|
(is (not (satisfies-protpath? FooPP 1)))
|
||||||
)))
|
)))
|
||||||
|
|
||||||
|
(deftest sorted-test
|
||||||
|
(let [initial-list [3 4 2 1]]
|
||||||
|
(testing "the SORTED navigator"
|
||||||
|
(is (= (sort initial-list) (select-one s/SORTED initial-list)))
|
||||||
|
(is (= [2 1 3 4] (transform s/SORTED reverse initial-list)))
|
||||||
|
(is (= [3 2 1] (transform s/SORTED butlast initial-list)))
|
||||||
|
(is (= [3 5 2 1] (setval [s/SORTED s/LAST] 5 initial-list)))
|
||||||
|
(is (= (list 1 2 3 4 5) (transform [s/SORTED s/ALL] inc (range 5)))))
|
||||||
|
(testing "the sorted navigator with comparator"
|
||||||
|
(let [reverse-comparator (comp - compare)]
|
||||||
|
(is (= (sort reverse-comparator initial-list)
|
||||||
|
(select-one (s/sorted reverse-comparator) initial-list)))
|
||||||
|
(is (= 4 (select-one [(s/sorted reverse-comparator) s/FIRST] initial-list))))))
|
||||||
|
(testing "the sorted-by navigator with keypath"
|
||||||
|
(let [initial-list [{:a 3} {:a 4} {:a 2} {:a 1}]]
|
||||||
|
(is (= (sort-by :a initial-list)
|
||||||
|
(select-one (s/sorted-by :a) initial-list)))
|
||||||
|
(is (= {:a 4} (select-one [(s/sorted-by :a (comp - compare)) s/FIRST] initial-list))))))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue