diff --git a/README.md b/README.md index 92e2cb0..228f917 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ More transducers and reducing functions for Clojure(script)! In `net.cgrand.xforms`: - * regular ones: `partition` (1 arg), `reductions`, `for`, `take-last`, `drop-last`, `window` and `window-by-time` + * regular ones: `partition` (1 arg), `reductions`, `for`, `take-last`, `drop-last`, `sort`, `sort-by`, `window` and `window-by-time` * higher-order ones: `by-key`, `into-by-key`, `multiplex`, `transjuxt`, `partition` (2+ args) * 1-item ones: `reduce`, `into`, `without`, `transjuxt`, `last`, `count`, `avg`, `sd`, `min`, `minimum`, `max`, `maximum`, `str` @@ -32,12 +32,14 @@ In `net.cgrand.xforms.io`: *Reducible views* (in `net.cgrand.xforms.io`): `lines-in` and `edn-in`. +**Note:** it should always be safe to update to the latest xforms version; short of bugfixes, breaking changes are avoided. + ## Usage Add this dependency to your project: ```clj -[net.cgrand/xforms "0.13.0"] +[net.cgrand/xforms "0.14.0"] ``` ```clj diff --git a/src/net/cgrand/xforms.cljc b/src/net/cgrand/xforms.cljc index 6d42da1..b496934 100644 --- a/src/net/cgrand/xforms.cljc +++ b/src/net/cgrand/xforms.cljc @@ -5,7 +5,7 @@ [net.cgrand.macrovich :as macros] [net.cgrand.xforms :refer [for kvrf let-complete]]) :clj (:require [net.cgrand.macrovich :as macros])) - (:refer-clojure :exclude [some reduce reductions into count for partition str last keys vals min max drop-last take-last]) + (:refer-clojure :exclude [some reduce reductions into count for partition str last keys vals min max drop-last take-last sort sort-by]) (:require [#?(:clj clojure.core :cljs cljs.core) :as core] [net.cgrand.xforms.rfs :as rf]) #?(:cljs (:import [goog.structs Queue]))) @@ -439,8 +439,26 @@ (if (< n (.size dq)) (rf acc (.poll dq)) acc))))))) + ) +(defn sort + ([] (sort compare)) + ([cmp] + (fn [rf] + (let [buf #?(:clj (java.util.ArrayList.) :cljs #js [])] + (fn + ([] (rf)) + ([acc] (rf (core/reduce rf acc (doto buf #?(:clj (java.util.Collections/sort cmp) :cljs (.sort cmp)))))) + ([acc x] (#?(:clj .add :cljs .push) buf x) acc)))))) + +(defn sort-by + ([kfn] (sort-by kfn compare)) + ([kfn cmp] + (sort (fn [a b] + #?(:clj (.compare ^java.util.Comparator cmp (kfn a) (kfn b)) + :cljs (cmp (kfn a) (kfn b))))))) + (defn reductions "Transducer version of reductions. There's a difference in behavior when init is not provided: (f) is used. So x/reductions works like x/reduce or transduce, not like reduce and reductions when no init and 1-item input." diff --git a/test/net/cgrand/xforms_test.cljc b/test/net/cgrand/xforms_test.cljc index be3b9c8..d3b0466 100644 --- a/test/net/cgrand/xforms_test.cljc +++ b/test/net/cgrand/xforms_test.cljc @@ -133,4 +133,10 @@ (deftest do-not-kvreduce-vectors (is (= {0 nil 1 nil} (x/into {} (x/for [[k v] %] [k v]) [[0] [1]]))) - (is (= {0 nil 1 nil} (x/into {} (x/for [_ % [k v] [[0] [1]]] [k v]) ["a"])))) \ No newline at end of file + (is (= {0 nil 1 nil} (x/into {} (x/for [_ % [k v] [[0] [1]]] [k v]) ["a"])))) + +(deftest sorting + (is (= (range 100) (x/into [] (x/sort) (shuffle (range 100))))) + (is (= (reverse (range 100)) (x/into [] (x/sort >) (shuffle (range 100))))) + (is (= (sort-by str (range 100)) (x/into [] (x/sort-by str) (shuffle (range 100))))) + (is (= (sort-by str (comp - compare) (range 100)) (x/into [] (x/sort-by str (comp - compare)) (shuffle (range 100)))))) \ No newline at end of file