diff --git a/src/clj/com/rpl/specter.cljc b/src/clj/com/rpl/specter.cljc index e031ed3..2894235 100644 --- a/src/clj/com/rpl/specter.cljc +++ b/src/clj/com/rpl/specter.cljc @@ -1504,3 +1504,61 @@ [& 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 late %) late-fn next-fn)) + (transform* [this structure next-fn] + (n/sorted-transform structure #(compiled-select late %) late-fn next-fn))))) diff --git a/src/clj/com/rpl/specter/impl.cljc b/src/clj/com/rpl/specter/impl.cljc index 2493271..7a21b78 100644 --- a/src/clj/com/rpl/specter/impl.cljc +++ b/src/clj/com/rpl/specter/impl.cljc @@ -546,6 +546,16 @@ 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 (concat indices (repeat ##Inf)) result))] + (into (empty structure) + (map second) + unsorted))) + (defn- matching-indices [aseq p] (keep-indexed (fn [i e] (if (p e) i)) aseq)) diff --git a/src/clj/com/rpl/specter/navs.cljc b/src/clj/com/rpl/specter/navs.cljc index 6465432..2a43338 100644 --- a/src/clj/com/rpl/specter/navs.cljc +++ b/src/clj/com/rpl/specter/navs.cljc @@ -381,6 +381,11 @@ (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] (cond (fn? path)