From 0515b711dfb3f5b2e650cd158addbb32d92ca525 Mon Sep 17 00:00:00 2001 From: Christophe Grand Date: Thu, 26 Oct 2017 18:09:32 +0200 Subject: [PATCH] 0.13.0 x/without, the opposite of x/into: dissoc/disj'ing instead of conj'ing. --- README.md | 6 +++--- project.clj | 2 +- src/net/cgrand/xforms.cljc | 36 ++++++++++++++++++++++++++++++++ test/net/cgrand/xforms_test.cljc | 4 ++++ 4 files changed, 44 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0973d00..92e2cb0 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ In `net.cgrand.xforms`: * regular ones: `partition` (1 arg), `reductions`, `for`, `take-last`, `drop-last`, `window` and `window-by-time` * higher-order ones: `by-key`, `into-by-key`, `multiplex`, `transjuxt`, `partition` (2+ args) - * 1-item ones: `reduce`, `into`, `transjuxt`, `last`, `count`, `avg`, `sd`, `min`, `minimum`, `max`, `maximum`, `str` + * 1-item ones: `reduce`, `into`, `without`, `transjuxt`, `last`, `count`, `avg`, `sd`, `min`, `minimum`, `max`, `maximum`, `str` In `net.cgrand.xforms.io`: * `sh` to use any process as a transducer @@ -27,7 +27,7 @@ In `net.cgrand.xforms.io`: *Transducing contexts*: - * in `net.cgrand.xforms`: `transjuxt` (for performing several transductions in a single pass), `iterator` (clojure only), `into`, `count` and `some`. + * in `net.cgrand.xforms`: `transjuxt` (for performing several transductions in a single pass), `iterator` (clojure only), `into`, `without`, `count` and `some`. * in `net.cgrand.xforms.io`: `line-out` (3+ args) and `edn-out` (3+ args). *Reducible views* (in `net.cgrand.xforms.io`): `lines-in` and `edn-in`. @@ -37,7 +37,7 @@ In `net.cgrand.xforms.io`: Add this dependency to your project: ```clj -[net.cgrand/xforms "0.12.1"] +[net.cgrand/xforms "0.13.0"] ``` ```clj diff --git a/project.clj b/project.clj index cafbad6..b969a04 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject net.cgrand/xforms "0.12.2" +(defproject net.cgrand/xforms "0.13.0" :description "Extra transducers for Clojure" :url "https://github.com/cgrand/xforms" :license {:name "Eclipse Public License" diff --git a/src/net/cgrand/xforms.cljc b/src/net/cgrand/xforms.cljc index f5dc0cf..6d42da1 100644 --- a/src/net/cgrand/xforms.cljc +++ b/src/net/cgrand/xforms.cljc @@ -196,6 +196,42 @@ (rf (core/reduce-kv rf (rf) from)) (rf (core/reduce rf (rf) from)))))) +(defn- without-rf [from] + (cond + #?(:clj (instance? clojure.lang.IEditableCollection from) + :cljs (satisfies? IEditableCollection from)) + (if (map? from) + (fn + ([] (transient from)) + ([acc] (persistent! acc)) + ([acc x] (dissoc! acc x))) + (fn + ([] (transient from)) + ([acc] (persistent! acc)) + ([acc x] (disj! acc x)))) + (map? from) + (fn + ([] from) + ([acc] acc) + ([acc x] (dissoc acc x))) + :else + (fn + ([] from) + ([acc] acc) + ([acc x] (disj acc x))))) + +(defn without + "The opposite of x/into: dissociate or disjoin from the target." + ([target] + (reduce (without-rf target))) + ([target keys] + (without target identity keys)) + ([target xform keys] + (let [rf (xform (without-rf target))] + (if-let [rf (and (map? keys) (kvreducible? keys) (some-kvrf rf))] + (rf (core/reduce-kv rf (rf) keys)) + (rf (core/reduce rf (rf) keys)))))) + (defn minimum ([comparator] (minimum comparator nil)) diff --git a/test/net/cgrand/xforms_test.cljc b/test/net/cgrand/xforms_test.cljc index 708d0a5..be3b9c8 100644 --- a/test/net/cgrand/xforms_test.cljc +++ b/test/net/cgrand/xforms_test.cljc @@ -90,6 +90,10 @@ (is (= (into [] (comp (x/partition 2 2 nil) (x/into [])) (range 8)) [[[0 1] [2 3] [4 5] [6 7]]]))) +(deftest without + (is (= {0 :ok 2 :ok 4 :ok 6 :ok 8 :ok} (x/without (zipmap (range 10) (repeat :ok)) (filter odd?) (range 20)))) + (is (= #{0 2 4 6 8 } (x/without (set (range 10)) (filter odd?) (range 20))))) + #?(:clj (deftest iterator (is (true? (.hasNext (x/iterator x/count (.iterator (range 5))))))