@thi.ng/transducers
Advanced tools
Comparing version 0.8.0 to 0.9.0
@@ -6,2 +6,4 @@ "use strict"; | ||
switch (fns.length) { | ||
case 0: | ||
throw new Error("no fn args given"); | ||
case 1: | ||
@@ -26,10 +28,5 @@ return a; | ||
case 10: | ||
return (x) => a(b(c(d(e(f(g(h(i(j(x)))))))))); | ||
default: | ||
return (x) => { | ||
for (let i = fns.length - 1; i >= 0; i--) { | ||
x = fns[i](x); | ||
} | ||
return x; | ||
}; | ||
let ff = (x) => a(b(c(d(e(f(g(h(i(j(x)))))))))); | ||
return fns.length === 10 ? ff : comp(ff, ...fns.slice(10)); | ||
} | ||
@@ -36,0 +33,0 @@ } |
@@ -9,1 +9,2 @@ export declare type Fn<A, B> = (x: A) => B; | ||
export declare function juxt<T, A, B, C, D, E, F, G>(a: Fn<T, A>, b: Fn<T, B>, c: Fn<T, C>, d: Fn<T, D>, e: Fn<T, E>, f: Fn<T, F>, g: Fn<T, G>): Fn<T, [A, B, C, D, E, F, G]>; | ||
export declare function juxt<T, A, B, C, D, E, F, G, H>(a: Fn<T, A>, b: Fn<T, B>, c: Fn<T, C>, d: Fn<T, D>, e: Fn<T, E>, f: Fn<T, F>, g: Fn<T, G>, h: Fn<T, H>): Fn<T, [A, B, C, D, E, F, G, H]>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
function juxt(...fns) { | ||
const [a, b, c, d] = fns; | ||
const [a, b, c, d, e, f, g, h] = fns; | ||
switch (fns.length) { | ||
@@ -14,5 +14,13 @@ case 1: | ||
return (x) => [a(x), b(x), c(x), d(x)]; | ||
case 5: | ||
return (x) => [a(x), b(x), c(x), d(x), e(x)]; | ||
case 6: | ||
return (x) => [a(x), b(x), c(x), d(x), e(x), f(x)]; | ||
case 7: | ||
return (x) => [a(x), b(x), c(x), d(x), e(x), f(x), g(x)]; | ||
case 8: | ||
return (x) => [a(x), b(x), c(x), d(x), e(x), f(x), g(x), h(x)]; | ||
default: | ||
return function (x) { | ||
let res = []; | ||
let res = new Array(fns.length); | ||
for (let i = fns.length - 1; i >= 0; i--) { | ||
@@ -19,0 +27,0 @@ res[i] = fns[i](x); |
@@ -26,2 +26,3 @@ export * from "./api"; | ||
export * from "./xform/benchmark"; | ||
export * from "./xform/bits"; | ||
export * from "./xform/cat"; | ||
@@ -38,2 +39,3 @@ export * from "./xform/dedupe"; | ||
export * from "./xform/flatten"; | ||
export * from "./xform/hex-dump"; | ||
export * from "./xform/indexed"; | ||
@@ -49,2 +51,3 @@ export * from "./xform/inspect"; | ||
export * from "./xform/moving-average"; | ||
export * from "./xform/pad-last"; | ||
export * from "./xform/partition-by"; | ||
@@ -70,2 +73,3 @@ export * from "./xform/partition-sort"; | ||
export * from "./func/delay"; | ||
export * from "./func/hex"; | ||
export * from "./func/identity"; | ||
@@ -76,2 +80,4 @@ export * from "./func/juxt"; | ||
export * from "./func/swizzler"; | ||
export * from "./func/weighted-random"; | ||
export * from "./iter/choices"; | ||
export * from "./iter/constantly"; | ||
@@ -78,0 +84,0 @@ export * from "./iter/cycle"; |
@@ -31,2 +31,3 @@ "use strict"; | ||
__export(require("./xform/benchmark")); | ||
__export(require("./xform/bits")); | ||
__export(require("./xform/cat")); | ||
@@ -43,2 +44,3 @@ __export(require("./xform/dedupe")); | ||
__export(require("./xform/flatten")); | ||
__export(require("./xform/hex-dump")); | ||
__export(require("./xform/indexed")); | ||
@@ -54,2 +56,3 @@ __export(require("./xform/inspect")); | ||
__export(require("./xform/moving-average")); | ||
__export(require("./xform/pad-last")); | ||
__export(require("./xform/partition-by")); | ||
@@ -75,2 +78,3 @@ __export(require("./xform/partition-sort")); | ||
__export(require("./func/delay")); | ||
__export(require("./func/hex")); | ||
__export(require("./func/identity")); | ||
@@ -81,2 +85,4 @@ __export(require("./func/juxt")); | ||
__export(require("./func/swizzler")); | ||
__export(require("./func/weighted-random")); | ||
__export(require("./iter/choices")); | ||
__export(require("./iter/constantly")); | ||
@@ -83,0 +89,0 @@ __export(require("./iter/cycle")); |
{ | ||
"name": "@thi.ng/transducers", | ||
"version": "0.8.0", | ||
"version": "0.9.0", | ||
"description": "Lightweight transducer implementations for ES6 / TypeScript", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
209
README.md
@@ -5,15 +5,33 @@ # @thi.ng/transducers | ||
Lightweight transducer implementations for ES6 / TypeScript (19KB minified, full lib). | ||
Lightweight transducer implementations for ES6 / TypeScript (21KB minified, full lib). | ||
Currently, the library provides altogether 65+ transducers, reducers and | ||
generators for composing data transformation pipelines. | ||
## TOC | ||
The overall concept and many of the functions offered here are directly | ||
- [Installation](#installation) | ||
- [Usage examples](#usage-examples) | ||
- [API](#api) | ||
- [Types](#types) | ||
- [Transformations](#transformations) | ||
- [Transducers](#transducers) | ||
- [Reducers](#reducers) | ||
- [Generators & iterators](#generators--iterators) | ||
- [License](#license) | ||
## About | ||
Currently, the library provides altogether 70+ transducers, reducers and | ||
sequence generators for composing data transformation pipelines. | ||
The overall concept and many of the core functions offered here are directly | ||
inspired by the original Clojure implementation by Rich Hickey, though the | ||
implementation does differ and several generally highly useful operators | ||
have been added, with more are to come. | ||
implementation does differ (also in contrast to some other JS based | ||
implementations) and several less common, but generally highly useful operators | ||
have been added, with at least a couple dozen more to come. | ||
Please see the [@thi.ng/iterators](https://github.com/thi-ng/iterators) & | ||
[@thi.ng/csp](https://github.com/thi-ng/csp) partner modules for related | ||
functionality, supplementing features of this library. | ||
functionality, supplementing features of this library. However, this lib has no | ||
dependencies on either of them. The only dependency is | ||
[@thi.ng/api](https://github.com/thi-ng/api) for re-using common types & | ||
interfaces. | ||
@@ -46,3 +64,6 @@ Having said this, since 0.8.0 this project largely supersedes the | ||
### Basic usage patterns | ||
```typescript | ||
// compose transducer | ||
xform = tx.comp( | ||
@@ -58,15 +79,42 @@ tx.filter(x => (x & 1) > 0), // odd numbers only | ||
// re-use xform, but collect as set (tx.conj) | ||
// re-use same xform, but collect as set (tx.conj) | ||
tx.transduce(xform, tx.conj(), [1, 2, 3, 4, 5, 4, 3, 2, 1]); | ||
// Set { 3, 9, 15 } | ||
// apply as transforming iterator | ||
for(let x of tx.iterator(xform, [1, 2, 3, 4, 5])) { | ||
console.log(x); | ||
} | ||
// 3 | ||
// 9 | ||
// 15 | ||
// or apply as transforming iterator | ||
// no reduction, only transformations | ||
[...tx.iterator(xform, [1, 2, 3, 4, 5])] | ||
// [ 3, 9, 15] | ||
// moving average using sliding window | ||
// single step execution | ||
// (currently doesn't work w/ mapcat(), duplicate() and some others) | ||
// returns undefined if transducer returned no result for this input | ||
f = tx.step(xform); | ||
f(1) // 3 | ||
f(2) // undefined | ||
f(3) // 9 | ||
f(4) // undefined | ||
f(5) // 15 | ||
f(4) // undefined | ||
f(3) // undefined | ||
f(2) // undefined | ||
f(1) // undefined | ||
``` | ||
### Histogram generation | ||
```typescript | ||
// use the `frequencies` reducer to create | ||
// a map counting occurrence of each value | ||
tx.transduce(tx.map(x => x.toUpperCase()), tx.frequencies(), "hello world") | ||
// Map { 'H' => 1, 'E' => 1, 'L' => 3, 'O' => 2, ' ' => 1, 'W' => 1, 'R' => 1, 'D' => 1 } | ||
// reduction only (no transform) | ||
tx.reduce(tx.frequencies(), [1, 1, 1, 2, 3, 4, 4]) | ||
// Map { 1 => 3, 2 => 1, 3 => 1, 4 => 2 } | ||
``` | ||
### Moving average using sliding window | ||
```typescript | ||
// use nested reduce to compute window averages | ||
@@ -84,4 +132,22 @@ // this combined transducer is also directly | ||
// [ 2.6, 3.4, 4, 4.6, 5.4, 6.2, 6.8, 7.6, 8.4 ] | ||
``` | ||
// apply inspectors to debug transducer pipeline | ||
### Benchmark function execution time | ||
```typescript | ||
// function to test | ||
fn = () => { for(i=0; i<1e6; i++) let x =Math.cos(i); return x; }; | ||
// compute the mean of 100 runs | ||
tx.transduce( | ||
tx.comp(tx.benchmark(), tx.take(100)), | ||
tx.mean(), | ||
tx.repeatedly(fn) | ||
); | ||
// 1.93 (milliseconds) | ||
``` | ||
### Apply inspectors to debug transducer pipeline | ||
```typescript | ||
// alternatively, use tx.sideEffect() for any side fx | ||
@@ -108,14 +174,7 @@ tx.transduce( | ||
// [ 3, 5 ] | ||
``` | ||
### CSV parsing | ||
// histogram generation | ||
tx.transduce(tx.map(x => x.toUpperCase()), tx.frequencies(), "hello world") | ||
// Map { 'H' => 1, 'E' => 1, 'L' => 3, 'O' => 2, ' ' => 1, 'W' => 1, 'R' => 1, 'D' => 1 } | ||
// reduction only (no transform) | ||
tx.reduce(tx.frequencies(), [1, 1, 1, 2, 3, 4, 4]) | ||
// Map { 1 => 3, 2 => 1, 3 => 1, 4 => 2 } | ||
// CSV parsing | ||
```typescript | ||
tx.transduce( | ||
@@ -136,5 +195,7 @@ tx.comp( | ||
// { num: 3, alias: 'rs', name: 'rust', id: '110' } ] | ||
``` | ||
### Early termination | ||
// early termination: | ||
```typescript | ||
// result is realized after max. 7 values, irrespective of nesting | ||
@@ -147,4 +208,7 @@ tx.transduce( | ||
// [1, 2, 3, 4, 5, 6, 7] | ||
``` | ||
### Scan operator | ||
```typescript | ||
// this transducer uses 2 scans (a scan = inner reducer per item) | ||
@@ -158,5 +222,5 @@ // 1) counts incoming values | ||
xform = tx.comp( | ||
tx.scan(tx.count), | ||
tx.map(x => [...tx.iterator(tx.repeat(x), [x])]), | ||
tx.scan(tx.pushCopy) | ||
tx.scan(tx.count()), | ||
tx.map(x => [...tx.repeat(x,x)]), | ||
tx.scan(tx.pushCopy()) | ||
); | ||
@@ -173,15 +237,58 @@ | ||
// [ [ 1 ], [ 1, 2 ], [ 1, 2, 3 ], [ 1, 2, 3, 4 ] ] | ||
``` | ||
// single step execution (doesn't work w/ mapcat() or repeat()) | ||
f = tx.step(tx.dedupe()); | ||
f(1); // 1 | ||
f(2); // 2 | ||
f(2); // undefined -> skip repetiton | ||
f(3); // 3 | ||
f(3); // undefined | ||
f(3); // undefined | ||
f(1); // 1 | ||
### Streaming hexdump | ||
This is a higher-order transducer, purely composed from other transducers. | ||
[See code here](https://github.com/thi-ng/transducers/blob/master/src/xform/hex-dump.ts). | ||
```typescript | ||
src = [65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 33, 48, 49, 50, 51, 126, 122, 121, 120] | ||
[...iterator(hexDump(8, 0x400), src)] | ||
// [ '00000400 | 41 42 43 44 45 46 47 48 | ABCDEFGH', | ||
// '00000408 | 49 4a 21 30 31 32 33 7e | IJ!0123~', | ||
// '00000410 | 7a 79 78 00 00 00 00 00 | zyx.....' ] | ||
``` | ||
### API | ||
### Bitstream | ||
```typescript | ||
[...tx.iterator(tx.comp(tx.bits(8), tx.partition(8)), [ 0xf0, 0xaa ])] | ||
// [ 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0 ] | ||
[...tx.iterator( | ||
tx.comp( | ||
tx.bits(8), | ||
tx.map(x=> x ? "#" : "."), | ||
tx.partition(8), | ||
tx.map(x=>x.join("")) | ||
), | ||
[ 0x00, 0x18, 0x3c, 0x66, 0x66, 0x7e, 0x66, 0x00 ])] | ||
// [ '........', | ||
// '...##...', | ||
// '..####..', | ||
// '.##..##.', | ||
// '.##..##.', | ||
// '.######.', | ||
// '.##..##.', | ||
// '........' ] | ||
``` | ||
### Weighted random choices | ||
```typescript | ||
tx.transduce(tx.take(10), tx.push(), tx.choices("abcd", [1, 0.5, 0.25, 0.125])) | ||
// [ 'a', 'a', 'b', 'a', 'a', 'b', 'a', 'c', 'd', 'b' ] | ||
tx.transduce(tx.take(1000), tx.frequencies(), tx.choices("abcd", [1, 0.5, 0.25, 0.125])) | ||
// Map { 'c' => 132, 'a' => 545, 'b' => 251, 'd' => 72 } | ||
``` | ||
## API | ||
_Documentation is slowly forthcoming in the form of doc comments (incl. code | ||
examples) for a small, but growing number the functions listed below. Please | ||
see source code for now._ | ||
### Types | ||
@@ -198,4 +305,4 @@ | ||
Since v0.6.0 the bundled reducers are all wrapped in functions to provide a | ||
uniform API (and some of them can be preconfigured). However, it's fine to | ||
define stateless reducers as constant arrays. | ||
uniform API (and some of them can be preconfigured and/or are stateful | ||
closures). However, it's fine to define stateless reducers as constant arrays. | ||
@@ -329,2 +436,4 @@ ```typescript | ||
#### `bits(wordSize?: number, msbFirst?: boolean): Transducer<number, number>` | ||
#### `cat<T>(): Transducer<T[], T>` | ||
@@ -352,2 +461,4 @@ | ||
#### `hexDump(cols?: number, addr?: number): Transducer<number, string>` | ||
#### `indexed<T>(): Transducer<T, [number, T]>` | ||
@@ -373,2 +484,4 @@ | ||
#### `padLast<T>(n: number, fill: T): Transducer<T, T>` | ||
#### `partition<T>(size: number, step?: number, all?: boolean): Transducer<T, T[]>` | ||
@@ -382,2 +495,4 @@ | ||
#### `rename<A, B>(kmap: IObjectOf<PropertyKey>, rfn?: Reducer<B, [PropertyKey, A]>): Transducer<A[], B>` | ||
#### `sample<T>(prob: number): Transducer<T, T>` | ||
@@ -417,3 +532,3 @@ | ||
#### `count(): Reducer<number, number>` | ||
#### `count(offset?: number, step?: number): Reducer<number, any>` | ||
@@ -432,2 +547,4 @@ #### `frequencies<T>(): Reducer<Map<T, number>, T>` | ||
#### `maxCompare<T>(ident: () => T, cmp: Comparator<T> = compare): Reducer<T, T>` | ||
#### `mean(): Reducer<number, number>` | ||
@@ -437,2 +554,4 @@ | ||
#### `minCompare<T>(ident: () => T, cmp: Comparator<T> = compare): Reducer<T, T>` | ||
#### `mul(): Reducer<number, number>` | ||
@@ -446,2 +565,4 @@ | ||
#### `choices<T>(choices: T[], weights?: number[])` | ||
#### `constantly<T>(x: T): IterableIterator<T>` | ||
@@ -448,0 +569,0 @@ |
import { Reducer } from "../api"; | ||
export declare function count(): Reducer<number, any>; | ||
export declare function count(offset?: number, step?: number): Reducer<number, any>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
function count() { | ||
function count(offset = 0, step = 1) { | ||
return [ | ||
() => 0, | ||
() => offset, | ||
(acc) => acc, | ||
(acc, _) => acc + 1, | ||
(acc, _) => acc + step, | ||
]; | ||
} | ||
exports.count = count; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
100288
179
2073
574