xforms 0.10.0: new io namespace, some as a transducing context (and a rf) too
This commit is contained in:
parent
8f04ad0748
commit
809f8f709b
5 changed files with 132 additions and 7 deletions
11
README.md
11
README.md
|
|
@ -12,16 +12,21 @@ More transducers and reducing functions for Clojure(script)!
|
||||||
* higher-order ones: `by-key`, `into-by-key`, `multiplex`, `transjuxt`, `partition` (2+ args)
|
* 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`, `transjuxt`, `last`, `count`, `avg`, `sd`, `min`, `minimum`, `max`, `maximum`, `str`
|
||||||
|
|
||||||
*Reducing functions* (in `net.cgrand.xforms.rfs`): `min`, `minimum`, `max`, `maximum`, `str`, `str!`, `avg`, `sd`, `juxt` and `last`.
|
*Reducing functions*
|
||||||
|
|
||||||
Transducing contexts: `transjuxt` (for performing several transductions in a single pass), `into`, `count`.
|
* in `net.cgrand.xforms.rfs`: `min`, `minimum`, `max`, `maximum`, `str`, `str!`, `avg`, `sd`, `last` and `some`.
|
||||||
|
* in `net.cgrand.xforms.io`: `line-out` and `edn-out`.
|
||||||
|
|
||||||
|
*Transducing contexts*: `transjuxt` (for performing several transductions in a single pass), `into`, `count` and `some`.
|
||||||
|
|
||||||
|
*Reducible views* (in `net.cgrand.xforms.io`): `lines-in` and `edn-in`.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Add this dependency to your project:
|
Add this dependency to your project:
|
||||||
|
|
||||||
```clj
|
```clj
|
||||||
[net.cgrand /xforms "0.9.5"]
|
[net.cgrand /xforms "0.10.0"]
|
||||||
```
|
```
|
||||||
|
|
||||||
```clj
|
```clj
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
(defproject net.cgrand/xforms "0.9.5"
|
(defproject net.cgrand/xforms "0.10.0"
|
||||||
:description "Extra transducers for Clojure"
|
:description "Extra transducers for Clojure"
|
||||||
:url "https://github.com/cgrand/xforms"
|
:url "https://github.com/cgrand/xforms"
|
||||||
:license {:name "Eclipse Public License"
|
:license {:name "Eclipse Public License"
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
[net.cgrand.macrovich :as macros]
|
[net.cgrand.macrovich :as macros]
|
||||||
[net.cgrand.xforms :refer [for kvrf let-complete]])
|
[net.cgrand.xforms :refer [for kvrf let-complete]])
|
||||||
:clj (:require [net.cgrand.macrovich :as macros]))
|
:clj (:require [net.cgrand.macrovich :as macros]))
|
||||||
(:refer-clojure :exclude [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])
|
||||||
(:require [#?(:clj clojure.core :cljs cljs.core) :as core]
|
(:require [#?(:clj clojure.core :cljs cljs.core) :as core]
|
||||||
[net.cgrand.xforms.rfs :as rf])
|
[net.cgrand.xforms.rfs :as rf])
|
||||||
#?(:cljs (:import [goog.structs Queue])))
|
#?(:cljs (:import [goog.structs Queue])))
|
||||||
|
|
@ -367,6 +367,10 @@
|
||||||
acc)
|
acc)
|
||||||
acc))))))))
|
acc))))))))
|
||||||
|
|
||||||
|
#_(defn zip [xform1 xform2]
|
||||||
|
(fn [rf]
|
||||||
|
(let )))
|
||||||
|
|
||||||
(defn take-last [n]
|
(defn take-last [n]
|
||||||
(fn [rf]
|
(fn [rf]
|
||||||
(let [dq (java.util.ArrayDeque. n)]
|
(let [dq (java.util.ArrayDeque. n)]
|
||||||
|
|
@ -460,7 +464,8 @@
|
||||||
|
|
||||||
#?(:clj
|
#?(:clj
|
||||||
(defn window-by-time
|
(defn window-by-time
|
||||||
"Returns a transducer which computes a windowed accumulator over chronologically sorted items.
|
"ALPHA
|
||||||
|
Returns a transducer which computes a windowed accumulator over chronologically sorted items.
|
||||||
|
|
||||||
timef is a function from one item to its scaled timestamp (as a double). The window length is always 1.0
|
timef is a function from one item to its scaled timestamp (as a double). The window length is always 1.0
|
||||||
so timef must normalize timestamps. For example if timestamps are in seconds (and under the :ts key),
|
so timef must normalize timestamps. For example if timestamps are in seconds (and under the :ts key),
|
||||||
|
|
@ -589,6 +594,11 @@
|
||||||
|
|
||||||
(def last (reduce rf/last))
|
(def last (reduce rf/last))
|
||||||
|
|
||||||
|
(defn some
|
||||||
|
"Process coll through the specified xform and returns the first local true value."
|
||||||
|
[xform coll]
|
||||||
|
(transduce xform rf/some nil coll))
|
||||||
|
|
||||||
(defn transjuxt
|
(defn transjuxt
|
||||||
"Performs several transductions over coll at once. xforms-map can be a map or a sequential collection.
|
"Performs several transductions over coll at once. xforms-map can be a map or a sequential collection.
|
||||||
When xforms-map is a map, returns a map with the same keyset as xforms-map.
|
When xforms-map is a map, returns a map with the same keyset as xforms-map.
|
||||||
|
|
@ -609,4 +619,25 @@
|
||||||
([xforms-map coll]
|
([xforms-map coll]
|
||||||
(transduce (transjuxt xforms-map) rf/last coll)))
|
(transduce (transjuxt xforms-map) rf/last coll)))
|
||||||
|
|
||||||
|
#_(defn rollup
|
||||||
|
"Roll-up input data along the provided dimensions (which are functions of one input item),
|
||||||
|
Values of interest are extracted from items using the valfn function and are then summarized
|
||||||
|
by summary-fn (a reducing function over values returned by valfn or summaries).
|
||||||
|
Each level of rollup is a map with two keys: :summary and :details."
|
||||||
|
([dimensions valfn summary-fn]
|
||||||
|
(let [[dim & dims] (reverse dimensions)]
|
||||||
|
(core/reduce
|
||||||
|
(fn [xform dim]
|
||||||
|
(comp
|
||||||
|
(by-key dim xform)
|
||||||
|
(transjuxt
|
||||||
|
{:detail (into {})
|
||||||
|
:summary (comp vals (map :summary) (reduce summary-fn))})))
|
||||||
|
(comp (by-key dim (map valfn))
|
||||||
|
(transjuxt
|
||||||
|
{:detail (into {})
|
||||||
|
:summary (comp vals (reduce summary-fn))}))
|
||||||
|
dims)))
|
||||||
|
([dimensions valfn summary-fn coll]
|
||||||
|
(into {} (rollup dimensions valfn summary-fn) coll)))
|
||||||
)
|
)
|
||||||
|
|
|
||||||
83
src/net/cgrand/xforms/io.clj
Normal file
83
src/net/cgrand/xforms/io.clj
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
(ns net.cgrand.xforms.io
|
||||||
|
(:require [clojure.java.io :as io]
|
||||||
|
[clojure.edn :as edn]))
|
||||||
|
|
||||||
|
(defn keep-opts [m like]
|
||||||
|
(let [ns (namespace like)]
|
||||||
|
(into {}
|
||||||
|
(keep (fn [[k v]]
|
||||||
|
(when (= ns (or (namespace k) ns))
|
||||||
|
[(keyword (name k)) v])))
|
||||||
|
m)))
|
||||||
|
|
||||||
|
(defn lines-in
|
||||||
|
"Returns a reducible view over the provided input.
|
||||||
|
Input is read line by line. Coercion of the input is done by io/reader (and opts are passed to it).
|
||||||
|
Input is automatically closed upon completion or error."
|
||||||
|
[in & opts]
|
||||||
|
(let [no-init (Object.)]
|
||||||
|
(reify clojure.lang.IReduce
|
||||||
|
(reduce [self f] (.reduce self f no-init))
|
||||||
|
(reduce [self f init]
|
||||||
|
(with-open [rdr (apply io/reader in opts)]
|
||||||
|
(let [rdr (cond-> rdr (not (instance? java.io.BufferedReader rdr)) java.io.BufferedReader.)
|
||||||
|
init (if (identical? init no-init)
|
||||||
|
(or (.readLine rdr) (f))
|
||||||
|
init)]
|
||||||
|
(loop [state init]
|
||||||
|
(if-some [line (.readLine rdr)]
|
||||||
|
(let [state (f state line)]
|
||||||
|
(if (reduced? state)
|
||||||
|
(unreduced state)
|
||||||
|
(recur state)))
|
||||||
|
state))))))))
|
||||||
|
|
||||||
|
(defn lines-out
|
||||||
|
"Reducing function that writes values serialized to its accumulator (a java.io.Writer).
|
||||||
|
Returns the writer."
|
||||||
|
([w] w)
|
||||||
|
([^java.io.Writer w line]
|
||||||
|
(doto w
|
||||||
|
(.write (str line))
|
||||||
|
(.newLine))))
|
||||||
|
|
||||||
|
(defn edn-in
|
||||||
|
"Returns a reducible view over the provided input.
|
||||||
|
Input is read line by line. Coercion of the input is done by io/reader (and opts are passed to it).
|
||||||
|
Input is automatically closed upon completion or error."
|
||||||
|
[in & {:as opts}]
|
||||||
|
(let [no-init (Object.)]
|
||||||
|
(reify clojure.lang.IReduce
|
||||||
|
(reduce [self f] (.reduce self f no-init))
|
||||||
|
(reduce [self f init]
|
||||||
|
(with-open [rdr (apply io/reader in (mapcat seq (keep-opts opts ::io/opts)))]
|
||||||
|
(let [rdr (cond-> rdr (not (instance? java.io.PushbackReader rdr)) java.io.PushbackReader.)
|
||||||
|
opts (assoc (keep-opts opts ::edn/opts) :eof no-init)
|
||||||
|
init (if (identical? init no-init)
|
||||||
|
(let [form (edn/read opts rdr)]
|
||||||
|
(if (identical? no-init form)
|
||||||
|
(f)
|
||||||
|
form))
|
||||||
|
init)]
|
||||||
|
(loop [state init]
|
||||||
|
(let [form (edn/read opts rdr)]
|
||||||
|
(if (identical? no-init form)
|
||||||
|
state
|
||||||
|
(let [state (f state form)]
|
||||||
|
(if (reduced? state)
|
||||||
|
(unreduced state)
|
||||||
|
(recur state))))))))))))
|
||||||
|
|
||||||
|
(defn edn-out
|
||||||
|
"Reducing function that writes values serialized as EDN to its accumulator (a java.io.Writer).
|
||||||
|
Returns the writer."
|
||||||
|
([w] w)
|
||||||
|
([^java.io.Writer w x]
|
||||||
|
(binding [*out* w
|
||||||
|
*print-length* nil
|
||||||
|
*print-level* nil
|
||||||
|
*print-dup* false
|
||||||
|
*print-meta* false
|
||||||
|
*print-readably* true]
|
||||||
|
(println x)
|
||||||
|
w)))
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
(ns net.cgrand.xforms.rfs
|
(ns net.cgrand.xforms.rfs
|
||||||
{:author "Christophe Grand"}
|
{:author "Christophe Grand"}
|
||||||
(:refer-clojure :exclude [str last min max])
|
(:refer-clojure :exclude [str last min max some])
|
||||||
#?(:cljs (:require-macros
|
#?(:cljs (:require-macros
|
||||||
[net.cgrand.macrovich :as macros]
|
[net.cgrand.macrovich :as macros]
|
||||||
[net.cgrand.xforms.rfs :refer [or-instance?]])
|
[net.cgrand.xforms.rfs :refer [or-instance?]])
|
||||||
|
|
@ -85,6 +85,12 @@
|
||||||
([x] x)
|
([x] x)
|
||||||
([_ x] x))
|
([_ x] x))
|
||||||
|
|
||||||
|
(defn some
|
||||||
|
"Reducing function that returns the first logical true value."
|
||||||
|
([] nil)
|
||||||
|
([x] x)
|
||||||
|
([_ x] (when x (reduced x))))
|
||||||
|
|
||||||
(defn str!
|
(defn str!
|
||||||
"Like xforms/str but returns a StringBuilder."
|
"Like xforms/str but returns a StringBuilder."
|
||||||
([] (#?(:clj StringBuilder. :cljs StringBuffer.)))
|
([] (#?(:clj StringBuilder. :cljs StringBuffer.)))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue