From 64eb4c6158ddfee8c5ac39dccea17a700d88c177 Mon Sep 17 00:00:00 2001 From: Christophe Grand Date: Thu, 2 Feb 2017 13:16:51 +0100 Subject: [PATCH] v0.9.0 add take-last and drop-last --- README.md | 4 ++-- project.clj | 2 +- src/net/cgrand/xforms.cljc | 35 ++++++++++++++++++++++++++++++++--- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2804214..607c4e1 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ More transducers and reducing functions for Clojure(script)! (which accept other transducers as arguments) and 1-item ones which emit only 1 item out no matter how many went in. They generally only make sense in the context of a higher-order transducer. - * regular ones: `partition` (1 arg), `reductions`, `for`, `window` and `window-by-time` + * regular ones: `partition` (1 arg), `reductions`, `for`, `take-last`, `drop-last`, `window` and `window-by-time` * higher-order ones: `by-key`, `multiplex`, `transjuxt`, `partition` (2+ args) * 1-item ones: `reduce`, `into`, `transjuxt`, `last`, `count`, `avg`, `sd`, `min`, `minimum`, `max`, `maximum`, `str` @@ -21,7 +21,7 @@ Transducing contexts: `transjuxt` (for performing several transductions in a sin Add this dependency to your project: ```clj -[net.cgrand/xforms "0.8.3"] +[net.cgrand/xforms "0.9.0"] ``` ```clj diff --git a/project.clj b/project.clj index 90e9a49..dc8a294 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject net.cgrand/xforms "0.8.3" +(defproject net.cgrand/xforms "0.9.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 bd48345..35f164e 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 [reduce reductions into count for partition str last keys vals min max]) + (:refer-clojure :exclude [reduce reductions into count for partition str last keys vals min max drop-last take-last]) (:require [#?(:clj clojure.core :cljs cljs.core) :as core] [net.cgrand.xforms.rfs :as rf]) #?(:cljs (:import [goog.structs Queue]))) @@ -276,7 +276,8 @@ (macros/replace [#?(:cljs {(java.util.ArrayDeque. n) (Queue.) .add .enqueue - .poll .dequeue}) + .poll .dequeue + .size .getCount}) #?(:clj {(.getValues dq) dq})] (defn partition @@ -334,7 +335,35 @@ (dotimes [_ (core/min n step)] (.poll dq)) (vswap! barrier + step) acc) - acc))))))))) + acc)))))))) + + (defn take-last [n] + (fn [rf] + (let [dq (java.util.ArrayDeque. n)] + (fn + ([] (rf)) + ([acc] (transduce (map #(if (identical? dq %) nil %)) rf acc (.getValues dq))) + ([acc x] + (.add dq (if (nil? x) dq x)) + (when (< n (.size dq)) (.poll dq)) + acc))))) + + (defn drop-last + ([] (drop-last 1)) + ([n] + (fn [rf] + (let [dq (java.util.ArrayDeque. n) + xform (map #(if (identical? dq %) nil %)) + rf (xform rf)] + (fn + ([] (rf)) + ([acc] (rf acc)) + ([acc x] + (.add dq (if (nil? x) dq x)) + (if (< n (.size dq)) + (rf acc (.poll dq)) + acc))))))) + ) (defn reductions "Transducer version of reductions. There's a difference in behavior when init is not provided: (f) is used.