@thi.ng/transducers
Advanced tools
Comparing version 0.5.3 to 0.6.0
142
index.d.ts
@@ -1,86 +0,56 @@ | ||
import { Comparator, IDeref, Predicate } from "@thi.ng/api"; | ||
export declare type Transducer<A, B> = (rfn: Reducer<any, B>) => Reducer<any, A>; | ||
export interface Reducer<A, B> extends Array<any> { | ||
[0]: () => A; | ||
[1]: (acc: A) => A; | ||
[2]: (acc: A, x: B) => A | Reduced<A>; | ||
} | ||
export declare class Reduced<T> implements IDeref<T> { | ||
protected value: T; | ||
constructor(val: T); | ||
deref(): T; | ||
} | ||
export declare function reduced(x: any): any; | ||
export declare function isReduced(x: any): boolean; | ||
export declare function ensureReduced(x: any): Reduced<any>; | ||
export declare function unreduced(x: any): any; | ||
export declare function comp<A, B>(a: Transducer<A, B>): Transducer<A, B>; | ||
export declare function comp<A, B, C>(a: Transducer<A, B>, b: Transducer<B, C>): Transducer<A, C>; | ||
export declare function comp<A, B, C, D>(a: Transducer<A, B>, b: Transducer<B, C>, c: Transducer<C, D>): Transducer<A, D>; | ||
export declare function comp<A, B, C, D, E>(a: Transducer<A, B>, b: Transducer<B, C>, c: Transducer<C, D>, d: Transducer<D, E>): Transducer<A, E>; | ||
export declare function comp<A, B, C, D, E, F>(a: Transducer<A, B>, b: Transducer<B, C>, c: Transducer<C, D>, d: Transducer<D, E>, e: Transducer<E, F>): Transducer<A, F>; | ||
export declare function comp<A, B, C, D, E, F, G>(a: Transducer<A, B>, b: Transducer<B, C>, c: Transducer<C, D>, d: Transducer<D, E>, e: Transducer<E, F>, f: Transducer<F, G>): Transducer<A, G>; | ||
export declare function comp<A, B, C, D, E, F, G, H>(a: Transducer<A, B>, b: Transducer<B, C>, c: Transducer<C, D>, d: Transducer<D, E>, e: Transducer<E, F>, f: Transducer<F, G>, g: Transducer<G, H>): Transducer<A, H>; | ||
export declare function comp<A, B, C, D, E, F, G, H, I>(a: Transducer<A, B>, b: Transducer<B, C>, c: Transducer<C, D>, d: Transducer<D, E>, e: Transducer<E, F>, f: Transducer<F, G>, g: Transducer<G, H>, h: Transducer<H, I>): Transducer<A, I>; | ||
export declare function comp<A, B, C, D, E, F, G, H, I, J>(a: Transducer<A, B>, b: Transducer<B, C>, c: Transducer<C, D>, d: Transducer<D, E>, e: Transducer<E, F>, f: Transducer<F, G>, g: Transducer<G, H>, h: Transducer<H, I>, i: Transducer<I, J>): Transducer<A, J>; | ||
export declare function comp<A, B, C, D, E, F, G, H, I, J, K>(a: Transducer<A, B>, b: Transducer<B, C>, c: Transducer<C, D>, d: Transducer<D, E>, e: Transducer<E, F>, f: Transducer<F, G>, g: Transducer<G, H>, h: Transducer<H, I>, i: Transducer<I, J>, j: Transducer<J, K>): Transducer<A, K>; | ||
export declare function comp<A, B, C, D, E, F, G, H, I, J, K>(a: Transducer<A, B>, b: Transducer<B, C>, c: Transducer<C, D>, d: Transducer<D, E>, e: Transducer<E, F>, f: Transducer<F, G>, g: Transducer<G, H>, h: Transducer<H, I>, i: Transducer<I, J>, j: Transducer<J, K>, ...fns: Transducer<any, any>[]): Transducer<A, any>; | ||
export declare function compR(rfn: Reducer<any, any>, fn: (acc, x) => any): Reducer<any, any>; | ||
export declare function identity<T>(x: T): T; | ||
export declare function step<A, B>(tx: Transducer<A, B>): (x: A) => B; | ||
export declare function reduce<A, B>(rfn: Reducer<A, B>, xs: Iterable<B>): A; | ||
export declare function reduce<A, B>(rfn: Reducer<A, B>, acc: A, xs: Iterable<B>): A; | ||
export declare function transduce<A, B, C>(tx: Transducer<A, B>, rfn: Reducer<C, B>, xs: Iterable<A>): C; | ||
export declare function transduce<A, B, C>(tx: Transducer<A, B>, rfn: Reducer<C, B>, acc: C, xs: Iterable<A>): C; | ||
export declare function iterator<A, B>(tx: Transducer<A, B>, xs: Iterable<A>): IterableIterator<B>; | ||
export declare function map<A, B>(fn: (x: A) => B): Transducer<A, B>; | ||
export declare function pluck(key: PropertyKey): Transducer<any, any>; | ||
export declare function selectKeys(keys: PropertyKey[]): Transducer<any, any>; | ||
export declare function mapIndexed<A, B>(fn: (i: number, x: A) => B): Transducer<A, B>; | ||
export declare function mapcat<A, B>(fn: (x: A) => Iterable<B>): Transducer<A, B>; | ||
export declare function cat<T>(): Transducer<T[], T>; | ||
export declare function flatten<T>(): Transducer<T | Iterable<T>, T>; | ||
export declare function flattenOnly<T>(pred: Predicate<T>): Transducer<T | Iterable<T>, T>; | ||
export declare function scan<A, B>(inner: Reducer<B, A>, acc?: B): Transducer<A, B>; | ||
export declare function filter<T>(pred: Predicate<T>): Transducer<T, T>; | ||
export declare function keep<T>(f?: ((x: T) => any)): Transducer<T, T>; | ||
export declare function throttle<T>(delay: number): Transducer<T, T>; | ||
export declare function delayed<T>(t: number): Transducer<T, Promise<T>>; | ||
export declare function bench(): Transducer<any, number>; | ||
export declare function sideEffect<T>(fn: (x: T) => void): Transducer<T, T>; | ||
export declare function inspect<T>(prefix?: string): Transducer<T, T>; | ||
export declare function distinct<T>(mapfn?: ((x: T) => any)): Transducer<T, T>; | ||
export declare function dedupe<T>(equiv?: (a: T, b: T) => boolean): Transducer<T, T>; | ||
export declare function interpose<A, B>(sep: B | (() => B)): Transducer<A, A | B>; | ||
export declare function interleave<A, B>(sep: B | (() => B)): Transducer<A, A | B>; | ||
export declare function take<T>(n: number): Transducer<T, T>; | ||
export declare function takeWhile<T>(pred: Predicate<T>): Transducer<T, T>; | ||
export declare function takeNth<T>(n: number): Transducer<T, T>; | ||
export declare function drop<T>(n: number): Transducer<T, T>; | ||
export declare function dropWhile<T>(pred: Predicate<T>): Transducer<T, T>; | ||
export declare function dropNth<T>(n: number): Transducer<T, T>; | ||
export declare function repeat<T>(n: number): Transducer<T, T>; | ||
export declare function sample<T>(prob: number): Transducer<T, T>; | ||
export declare function partition<T>(size: number): Transducer<T, T[]>; | ||
export declare function partition<T>(size: number, all: boolean): Transducer<T, T[]>; | ||
export declare function partition<T>(size: number, step: number): Transducer<T, T[]>; | ||
export declare function partition<T>(size: number, step: number, all: boolean): Transducer<T, T[]>; | ||
export declare function partitionBy<T>(fn: (x: T) => any): Transducer<T, T[]>; | ||
export declare function chunkSort<T>(n: number, key?: ((x: T) => any), cmp?: Comparator<any>): Transducer<T, T>; | ||
export declare function streamSort<T>(n: number, key?: ((x: T) => any), cmp?: Comparator<any>): Transducer<T, T>; | ||
export declare function streamShuffle<T>(n: number, maxSwaps?: number): Transducer<T, T>; | ||
export declare const push: Reducer<any[], any>; | ||
export declare const pushCopy: Reducer<any[], any>; | ||
export declare const conj: Reducer<Set<any>, any>; | ||
export declare const assocObj: Reducer<any, [PropertyKey, any]>; | ||
export declare const assocMap: Reducer<Map<any, any>, [any, any]>; | ||
export declare const add: Reducer<number, number>; | ||
export declare const count: Reducer<number, number>; | ||
export declare const mul: Reducer<number, number>; | ||
export declare function mean(): Reducer<number, number>; | ||
export declare const min: Reducer<number, number>; | ||
export declare const max: Reducer<number, number>; | ||
export declare function minCompare<T>(ident: () => T, cmp?: Comparator<T>): Reducer<T, T>; | ||
export declare function maxCompare<T>(ident: () => T, cmp?: Comparator<T>): Reducer<T, T>; | ||
export declare const frequencies: Reducer<Map<any, number>, any>; | ||
export declare const last: Reducer<any, any>; | ||
export * from "./api"; | ||
export * from "./comp"; | ||
export * from "./iterator"; | ||
export * from "./reduce"; | ||
export * from "./reduced"; | ||
export * from "./transduce"; | ||
export * from "./rfn/add"; | ||
export * from "./rfn/assoc-map"; | ||
export * from "./rfn/assoc-obj"; | ||
export * from "./rfn/conj"; | ||
export * from "./rfn/count"; | ||
export * from "./rfn/frequencies"; | ||
export * from "./rfn/last"; | ||
export * from "./rfn/max-compare"; | ||
export * from "./rfn/max"; | ||
export * from "./rfn/mean"; | ||
export * from "./rfn/min-compare"; | ||
export * from "./rfn/min"; | ||
export * from "./rfn/mul"; | ||
export * from "./rfn/push-copy"; | ||
export * from "./rfn/push"; | ||
export * from "./xform/benchmark"; | ||
export * from "./xform/cat"; | ||
export * from "./xform/chunk-sort"; | ||
export * from "./xform/dedupe"; | ||
export * from "./xform/delayed"; | ||
export * from "./xform/distinct"; | ||
export * from "./xform/drop-nth"; | ||
export * from "./xform/drop-while"; | ||
export * from "./xform/drop"; | ||
export * from "./xform/filter"; | ||
export * from "./xform/flatten-with"; | ||
export * from "./xform/flatten"; | ||
export * from "./xform/inspect"; | ||
export * from "./xform/interleave"; | ||
export * from "./xform/interpose"; | ||
export * from "./xform/keep"; | ||
export * from "./xform/map-indexed"; | ||
export * from "./xform/map"; | ||
export * from "./xform/mapcat"; | ||
export * from "./xform/moving-average"; | ||
export * from "./xform/partition-by"; | ||
export * from "./xform/partition"; | ||
export * from "./xform/pluck"; | ||
export * from "./xform/rename"; | ||
export * from "./xform/repeat"; | ||
export * from "./xform/sample"; | ||
export * from "./xform/scan"; | ||
export * from "./xform/select-keys"; | ||
export * from "./xform/side-effect"; | ||
export * from "./xform/stream-shuffle"; | ||
export * from "./xform/stream-sort"; | ||
export * from "./xform/take-nth"; | ||
export * from "./xform/take-while"; | ||
export * from "./xform/take"; | ||
export * from "./xform/throttle"; |
733
index.js
"use strict"; | ||
function __export(m) { | ||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; | ||
} | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const compare_1 = require("@thi.ng/api/compare"); | ||
; | ||
class Reduced { | ||
constructor(val) { | ||
this.value = val; | ||
} | ||
deref() { | ||
return this.value; | ||
} | ||
} | ||
exports.Reduced = Reduced; | ||
function reduced(x) { | ||
return new Reduced(x); | ||
} | ||
exports.reduced = reduced; | ||
function isReduced(x) { | ||
return x instanceof Reduced; | ||
} | ||
exports.isReduced = isReduced; | ||
function ensureReduced(x) { | ||
return x instanceof Reduced ? x : new Reduced(x); | ||
} | ||
exports.ensureReduced = ensureReduced; | ||
function unreduced(x) { | ||
return x instanceof Reduced ? x.deref() : x; | ||
} | ||
exports.unreduced = unreduced; | ||
function comp(...fns) { | ||
let [a, b, c, d, e, f, g, h, i, j] = fns; | ||
switch (fns.length) { | ||
case 1: | ||
return a; | ||
case 2: | ||
return (x) => a(b(x)); | ||
case 3: | ||
return (x) => a(b(c(x))); | ||
case 4: | ||
return (x) => a(b(c(d(x)))); | ||
case 5: | ||
return (x) => a(b(c(d(e(x))))); | ||
case 6: | ||
return (x) => a(b(c(d(e(f(x)))))); | ||
case 7: | ||
return (x) => a(b(c(d(e(f(g(x))))))); | ||
case 8: | ||
return (x) => a(b(c(d(e(f(g(h(x)))))))); | ||
case 9: | ||
return (x) => a(b(c(d(e(f(g(h(i(x))))))))); | ||
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; | ||
}; | ||
} | ||
} | ||
exports.comp = comp; | ||
function compR(rfn, fn) { | ||
return [ | ||
() => rfn[0](), | ||
(acc) => rfn[1](acc), | ||
fn, | ||
]; | ||
} | ||
exports.compR = compR; | ||
function identity(x) { | ||
return x; | ||
} | ||
exports.identity = identity; | ||
function step(tx) { | ||
const rfn = tx(exports.last)[2]; | ||
return (x) => rfn(undefined, x); | ||
} | ||
exports.step = step; | ||
function reduce(...args) { | ||
let acc, xs; | ||
switch (args.length) { | ||
case 3: | ||
xs = args[2]; | ||
acc = args[1]; | ||
break; | ||
case 2: | ||
xs = args[1]; | ||
break; | ||
default: | ||
throw new Error(`illegal arity ${args.length}`); | ||
} | ||
const [i, c, r] = args[0]; | ||
acc = acc == null ? i() : acc; | ||
for (let x of xs) { | ||
acc = r(acc, x); | ||
if (isReduced(acc)) { | ||
acc = acc.deref(); | ||
break; | ||
} | ||
} | ||
return unreduced(c(acc)); | ||
} | ||
exports.reduce = reduce; | ||
function transduce(...args) { | ||
let acc, xs; | ||
switch (args.length) { | ||
case 4: | ||
xs = args[3]; | ||
acc = args[2]; | ||
break; | ||
case 3: | ||
xs = args[2]; | ||
break; | ||
default: | ||
throw new Error(`illegal arity ${args.length}`); | ||
} | ||
const _rfn = args[0](args[1]); | ||
return reduce(_rfn, acc, xs); | ||
} | ||
exports.transduce = transduce; | ||
function* iterator(tx, xs) { | ||
const [_, c, r] = tx(exports.push); | ||
for (let x of xs) { | ||
const y = r([], x); | ||
if (isReduced(y)) { | ||
yield* unreduced(c(y.deref())); | ||
return; | ||
} | ||
if (y.length) { | ||
yield* y; | ||
} | ||
} | ||
yield* unreduced(c([])); | ||
} | ||
exports.iterator = iterator; | ||
function map(fn) { | ||
return (rfn) => { | ||
const r = rfn[2]; | ||
return compR(rfn, (acc, x) => r(acc, fn(x))); | ||
}; | ||
} | ||
exports.map = map; | ||
function pluck(key) { | ||
return map((x) => x[key]); | ||
} | ||
exports.pluck = pluck; | ||
function selectKeys(keys) { | ||
const [a, b, c] = keys; | ||
switch (keys.length) { | ||
case 0: | ||
throw new Error("no keys given"); | ||
case 1: | ||
return map((x) => x.hasOwnProperty(a) ? { [a]: x[a] } : {}); | ||
case 2: | ||
return map((x) => { | ||
const res = {}; | ||
x.hasOwnProperty(a) && (res[a] = x[a]); | ||
x.hasOwnProperty(b) && (res[b] = x[b]); | ||
return res; | ||
}); | ||
case 3: | ||
return map((x) => { | ||
const res = {}; | ||
x.hasOwnProperty(a) && (res[a] = x[a]); | ||
x.hasOwnProperty(b) && (res[b] = x[b]); | ||
x.hasOwnProperty(c) && (res[c] = x[c]); | ||
return res; | ||
}); | ||
default: | ||
return map((x) => { | ||
const res = {}; | ||
for (let i = keys.length - 1; i >= 0; i--) { | ||
const k = keys[i]; | ||
x.hasOwnProperty(k) && (res[k] = x[k]); | ||
} | ||
return res; | ||
}); | ||
} | ||
} | ||
exports.selectKeys = selectKeys; | ||
function mapIndexed(fn) { | ||
return (rfn) => { | ||
const r = rfn[2]; | ||
let i = 0; | ||
return compR(rfn, (acc, x) => r(acc, fn(i++, x))); | ||
}; | ||
} | ||
exports.mapIndexed = mapIndexed; | ||
function mapcat(fn) { | ||
return comp(map(fn), cat()); | ||
} | ||
exports.mapcat = mapcat; | ||
function cat() { | ||
return (rfn) => { | ||
const r = rfn[2]; | ||
return compR(rfn, (acc, x) => { | ||
if (x) { | ||
for (let y of x) { | ||
acc = r(acc, y); | ||
if (isReduced(acc)) { | ||
break; | ||
} | ||
} | ||
} | ||
return acc; | ||
}); | ||
}; | ||
} | ||
exports.cat = cat; | ||
function flatten() { | ||
return flattenOnly((x) => x != null && x[Symbol.iterator] && typeof x !== "string"); | ||
} | ||
exports.flatten = flatten; | ||
function flattenOnly(pred) { | ||
return (rfn) => { | ||
const r = rfn[2], fn = (acc, x) => { | ||
if (pred(x)) { | ||
for (let y of x) { | ||
acc = fn(acc, y); | ||
if (isReduced(acc)) { | ||
break; | ||
} | ||
} | ||
return acc; | ||
} | ||
return r(acc, x); | ||
}; | ||
return compR(rfn, fn); | ||
}; | ||
} | ||
exports.flattenOnly = flattenOnly; | ||
function scan(inner, acc) { | ||
return (outer) => { | ||
acc = acc || inner[0](); | ||
const ri = inner[2], ro = outer[2]; | ||
return compR(outer, (_acc, x) => { | ||
acc = ri(acc, x); | ||
if (isReduced(acc)) { | ||
return ensureReduced(ro(_acc, acc.deref())); | ||
} | ||
return ro(_acc, acc); | ||
}); | ||
}; | ||
} | ||
exports.scan = scan; | ||
function filter(pred) { | ||
return (rfn) => { | ||
const r = rfn[2]; | ||
return compR(rfn, (acc, x) => pred(x) ? r(acc, x) : acc); | ||
}; | ||
} | ||
exports.filter = filter; | ||
function keep(f = identity) { | ||
return (rfn) => { | ||
const r = rfn[2]; | ||
return compR(rfn, (acc, x) => f(x) != null ? r(acc, x) : acc); | ||
}; | ||
} | ||
exports.keep = keep; | ||
function throttle(delay) { | ||
return (rfn) => { | ||
const r = rfn[2]; | ||
let last = 0; | ||
return compR(rfn, (acc, x) => { | ||
const t = Date.now(); | ||
if (t - last >= delay) { | ||
last = t; | ||
acc = r(acc, x); | ||
} | ||
return acc; | ||
}); | ||
}; | ||
} | ||
exports.throttle = throttle; | ||
function delayed(t) { | ||
return map((x) => new Promise((resolve) => setTimeout(() => resolve(x), t))); | ||
} | ||
exports.delayed = delayed; | ||
function bench() { | ||
return (rfn) => { | ||
const r = rfn[2]; | ||
let prev; | ||
return compR(rfn, (acc, _) => { | ||
let t = Date.now(), x = prev ? t - prev : 0; | ||
prev = t; | ||
return r(acc, x); | ||
}); | ||
}; | ||
} | ||
exports.bench = bench; | ||
function sideEffect(fn) { | ||
return map((x) => (fn(x), x)); | ||
} | ||
exports.sideEffect = sideEffect; | ||
function inspect(prefix = "") { | ||
return sideEffect((x) => console.log(prefix, x)); | ||
} | ||
exports.inspect = inspect; | ||
function distinct(mapfn = identity) { | ||
return (rfn) => { | ||
const r = rfn[2]; | ||
const seen = new Set(); | ||
return compR(rfn, mapfn ? | ||
(acc, x) => { | ||
const k = mapfn(x); | ||
return !seen.has(k) ? (seen.add(k), r(acc, x)) : acc; | ||
} : | ||
(acc, x) => !seen.has(x) ? (seen.add(x), r(acc, x)) : acc); | ||
}; | ||
} | ||
exports.distinct = distinct; | ||
const SEMAPHORE = Symbol("SEMAPHORE"); | ||
function dedupe(equiv) { | ||
return (rfn) => { | ||
const r = rfn[2]; | ||
let prev = SEMAPHORE; | ||
return compR(rfn, equiv ? | ||
(acc, x) => { | ||
acc = equiv(prev, x) ? acc : r(acc, x); | ||
prev = x; | ||
return acc; | ||
} : | ||
(acc, x) => { | ||
acc = prev === x ? acc : r(acc, x); | ||
prev = x; | ||
return acc; | ||
}); | ||
}; | ||
} | ||
exports.dedupe = dedupe; | ||
function interpose(sep) { | ||
return (rfn) => { | ||
const r = rfn[2]; | ||
const _sep = typeof sep === "function" ? sep : () => sep; | ||
let first = true; | ||
return compR(rfn, (acc, x) => { | ||
if (first) { | ||
first = false; | ||
return r(acc, x); | ||
} | ||
acc = r(acc, _sep()); | ||
return isReduced(acc) ? acc : r(acc, x); | ||
}); | ||
}; | ||
} | ||
exports.interpose = interpose; | ||
function interleave(sep) { | ||
return (rfn) => { | ||
const r = rfn[2]; | ||
const _sep = typeof sep === "function" ? sep : () => sep; | ||
return compR(rfn, (acc, x) => { | ||
acc = r(acc, _sep()); | ||
return isReduced(acc) ? acc : r(acc, x); | ||
}); | ||
}; | ||
} | ||
exports.interleave = interleave; | ||
function take(n) { | ||
return (rfn) => { | ||
const r = rfn[2]; | ||
let m = n; | ||
return compR(rfn, (acc, x) => --m > 0 ? r(acc, x) : | ||
m === 0 ? ensureReduced(r(acc, x)) : | ||
reduced(acc)); | ||
}; | ||
} | ||
exports.take = take; | ||
function takeWhile(pred) { | ||
return (rfn) => { | ||
const r = rfn[2]; | ||
let ok = true; | ||
return compR(rfn, (acc, x) => (ok = ok && pred(x)) ? r(acc, x) : reduced(acc)); | ||
}; | ||
} | ||
exports.takeWhile = takeWhile; | ||
function takeNth(n) { | ||
n--; | ||
return (rfn) => { | ||
const r = rfn[2]; | ||
let skip = 0; | ||
return compR(rfn, (acc, x) => { | ||
if (skip === 0) { | ||
skip = n; | ||
return r(acc, x); | ||
} | ||
skip--; | ||
return acc; | ||
}); | ||
}; | ||
} | ||
exports.takeNth = takeNth; | ||
function drop(n) { | ||
return (rfn) => { | ||
const r = rfn[2]; | ||
let m = n; | ||
return compR(rfn, (acc, x) => m > 0 ? (m--, acc) : r(acc, x)); | ||
}; | ||
} | ||
exports.drop = drop; | ||
function dropWhile(pred) { | ||
return (rfn) => { | ||
const r = rfn[2]; | ||
let ok = true; | ||
return compR(rfn, (acc, x) => (ok = ok && pred(x)) ? acc : r(acc, x)); | ||
}; | ||
} | ||
exports.dropWhile = dropWhile; | ||
function dropNth(n) { | ||
n--; | ||
return (rfn) => { | ||
const r = rfn[2]; | ||
let skip = n; | ||
return compR(rfn, (acc, x) => { | ||
if (skip-- > 0) { | ||
return r(acc, x); | ||
} | ||
skip = n; | ||
return acc; | ||
}); | ||
}; | ||
} | ||
exports.dropNth = dropNth; | ||
function repeat(n) { | ||
return (rfn) => { | ||
const r = rfn[2]; | ||
return compR(rfn, (acc, x) => { | ||
for (let i = n; i > 0 && !isReduced(acc); i--) { | ||
acc = r(acc, x); | ||
} | ||
return acc; | ||
}); | ||
}; | ||
} | ||
exports.repeat = repeat; | ||
function sample(prob) { | ||
return (rfn) => { | ||
const r = rfn[2]; | ||
return compR(rfn, (acc, x) => Math.random() < prob ? r(acc, x) : acc); | ||
}; | ||
} | ||
exports.sample = sample; | ||
function partition(...args) { | ||
let size = args[0], all, step; | ||
if (typeof args[1] == "number") { | ||
step = args[1]; | ||
all = args[2]; | ||
} | ||
else { | ||
step = size; | ||
all = args[1]; | ||
} | ||
return (rfn) => { | ||
const r = rfn[2]; | ||
let buf = [], skip = 0; | ||
return [ | ||
() => rfn[0](), | ||
(acc) => { | ||
if (buf.length && (all || buf.length === size)) { | ||
acc = r(acc, buf); | ||
buf = []; | ||
} | ||
return rfn[1](acc); | ||
}, | ||
(acc, x) => { | ||
if (skip <= 0) { | ||
if (buf.length < size) { | ||
buf.push(x); | ||
} | ||
if (buf.length === size) { | ||
acc = r(acc, buf); | ||
buf = step < size ? buf.slice(step) : []; | ||
skip = step - size; | ||
} | ||
} | ||
else { | ||
skip--; | ||
} | ||
return acc; | ||
} | ||
]; | ||
}; | ||
} | ||
exports.partition = partition; | ||
function partitionBy(fn) { | ||
return (rfn) => { | ||
const r = rfn[2]; | ||
let prev = {}, chunk; | ||
return [ | ||
() => rfn[0](), | ||
(acc) => { | ||
if (chunk && chunk.length) { | ||
acc = r(acc, chunk); | ||
chunk = null; | ||
} | ||
return rfn[1](acc); | ||
}, | ||
(acc, x) => { | ||
const curr = fn(x); | ||
if (curr === prev) { | ||
chunk.push(x); | ||
} | ||
else { | ||
chunk && (acc = r(acc, chunk)); | ||
chunk = isReduced(acc) ? null : [x]; | ||
prev = curr; | ||
} | ||
return acc; | ||
} | ||
]; | ||
}; | ||
} | ||
exports.partitionBy = partitionBy; | ||
function chunkSort(n, key = identity, cmp = compare_1.compare) { | ||
return comp(partition(n, n, true), mapcat((chunk) => chunk.sort((a, b) => cmp(key(a), key(b))))); | ||
} | ||
exports.chunkSort = chunkSort; | ||
function binarySearch(arr, key, cmp, x) { | ||
const kx = key(x); | ||
let low = 0, high = arr.length - 1; | ||
while (low <= high) { | ||
const mid = (low + high) >>> 1, c = cmp(key(arr[mid]), kx); | ||
if (c < 0) { | ||
low = mid + 1; | ||
} | ||
else if (c > 0) { | ||
high = mid - 1; | ||
} | ||
else { | ||
return mid; | ||
} | ||
} | ||
return low; | ||
} | ||
function streamSort(n, key = identity, cmp = compare_1.compare) { | ||
return ([i, c, r]) => { | ||
const buf = []; | ||
return [ | ||
() => i(), | ||
(acc) => { | ||
while (buf.length && !isReduced(acc)) { | ||
acc = r(acc, buf.shift()); | ||
} | ||
acc = c(acc); | ||
return acc; | ||
}, | ||
(acc, x) => { | ||
buf.splice(binarySearch(buf, key, cmp, x), 0, x); | ||
if (buf.length === n) { | ||
acc = r(acc, buf.shift()); | ||
} | ||
return acc; | ||
} | ||
]; | ||
}; | ||
} | ||
exports.streamSort = streamSort; | ||
function shuffle(buf, n) { | ||
const l = buf.length; | ||
n = n < l ? n : l; | ||
while (--n >= 0) { | ||
const a = (Math.random() * l) | 0, b = (Math.random() * l) | 0, t = buf[a]; | ||
buf[a] = buf[b]; | ||
buf[b] = t; | ||
} | ||
} | ||
function streamShuffle(n, maxSwaps = n) { | ||
return ([i, c, r]) => { | ||
const buf = []; | ||
return [ | ||
() => i(), | ||
(acc) => { | ||
while (buf.length && !isReduced(acc)) { | ||
shuffle(buf, maxSwaps); | ||
acc = r(acc, buf.shift()); | ||
} | ||
acc = c(acc); | ||
return acc; | ||
}, | ||
(acc, x) => { | ||
buf.push(x); | ||
shuffle(buf, maxSwaps); | ||
if (buf.length === n) { | ||
acc = r(acc, buf.shift()); | ||
} | ||
return acc; | ||
} | ||
]; | ||
}; | ||
} | ||
exports.streamShuffle = streamShuffle; | ||
exports.push = [ | ||
() => [], | ||
(acc) => acc, | ||
(acc, x) => (acc.push(x), acc), | ||
]; | ||
exports.pushCopy = [ | ||
() => [], | ||
(acc) => acc, | ||
(acc, x) => ((acc = acc.slice()).push(x), acc) | ||
]; | ||
exports.conj = [ | ||
() => new Set(), | ||
(acc) => acc, | ||
(acc, x) => acc.add(x), | ||
]; | ||
exports.assocObj = [ | ||
() => new Object(), | ||
(acc) => acc, | ||
(acc, [k, v]) => (acc[k] = v, acc), | ||
]; | ||
exports.assocMap = [ | ||
() => new Map(), | ||
(acc) => acc, | ||
(acc, [k, v]) => acc.set(k, v), | ||
]; | ||
exports.add = [ | ||
() => 0, | ||
(acc) => acc, | ||
(acc, x) => acc + x, | ||
]; | ||
exports.count = [ | ||
() => 0, | ||
(acc) => acc, | ||
(acc, _) => acc + 1, | ||
]; | ||
exports.mul = [ | ||
() => 1, | ||
(acc) => acc, | ||
(acc, x) => acc * x, | ||
]; | ||
function mean() { | ||
let n = 0; | ||
return [ | ||
() => 0, | ||
(acc) => acc / n, | ||
(acc, x) => (n++, acc + x), | ||
]; | ||
} | ||
exports.mean = mean; | ||
exports.min = [ | ||
() => Number.POSITIVE_INFINITY, | ||
(acc) => acc, | ||
(acc, x) => Math.min(acc, x), | ||
]; | ||
exports.max = [ | ||
() => Number.NEGATIVE_INFINITY, | ||
(acc) => acc, | ||
(acc, x) => Math.max(acc, x), | ||
]; | ||
function minCompare(ident, cmp = compare_1.compare) { | ||
return [ | ||
ident, | ||
(acc) => acc, | ||
(acc, x) => cmp(acc, x) <= 0 ? acc : x | ||
]; | ||
} | ||
exports.minCompare = minCompare; | ||
function maxCompare(ident, cmp = compare_1.compare) { | ||
return [ | ||
ident, | ||
(acc) => acc, | ||
(acc, x) => cmp(acc, x) >= 0 ? acc : x | ||
]; | ||
} | ||
exports.maxCompare = maxCompare; | ||
exports.frequencies = [ | ||
() => new Map(), | ||
(acc) => acc, | ||
(acc, x) => acc.set(x, acc.has(x) ? acc.get(x) + 1 : 1) | ||
]; | ||
exports.last = [ | ||
() => undefined, | ||
(acc) => acc, | ||
(_, x) => x, | ||
]; | ||
__export(require("./api")); | ||
__export(require("./comp")); | ||
__export(require("./iterator")); | ||
__export(require("./reduce")); | ||
__export(require("./reduced")); | ||
__export(require("./transduce")); | ||
__export(require("./rfn/add")); | ||
__export(require("./rfn/assoc-map")); | ||
__export(require("./rfn/assoc-obj")); | ||
__export(require("./rfn/conj")); | ||
__export(require("./rfn/count")); | ||
__export(require("./rfn/frequencies")); | ||
__export(require("./rfn/last")); | ||
__export(require("./rfn/max-compare")); | ||
__export(require("./rfn/max")); | ||
__export(require("./rfn/mean")); | ||
__export(require("./rfn/min-compare")); | ||
__export(require("./rfn/min")); | ||
__export(require("./rfn/mul")); | ||
__export(require("./rfn/push-copy")); | ||
__export(require("./rfn/push")); | ||
__export(require("./xform/benchmark")); | ||
__export(require("./xform/cat")); | ||
__export(require("./xform/chunk-sort")); | ||
__export(require("./xform/dedupe")); | ||
__export(require("./xform/delayed")); | ||
__export(require("./xform/distinct")); | ||
__export(require("./xform/drop-nth")); | ||
__export(require("./xform/drop-while")); | ||
__export(require("./xform/drop")); | ||
__export(require("./xform/filter")); | ||
__export(require("./xform/flatten-with")); | ||
__export(require("./xform/flatten")); | ||
__export(require("./xform/inspect")); | ||
__export(require("./xform/interleave")); | ||
__export(require("./xform/interpose")); | ||
__export(require("./xform/keep")); | ||
__export(require("./xform/map-indexed")); | ||
__export(require("./xform/map")); | ||
__export(require("./xform/mapcat")); | ||
__export(require("./xform/moving-average")); | ||
__export(require("./xform/partition-by")); | ||
__export(require("./xform/partition")); | ||
__export(require("./xform/pluck")); | ||
__export(require("./xform/rename")); | ||
__export(require("./xform/repeat")); | ||
__export(require("./xform/sample")); | ||
__export(require("./xform/scan")); | ||
__export(require("./xform/select-keys")); | ||
__export(require("./xform/side-effect")); | ||
__export(require("./xform/stream-shuffle")); | ||
__export(require("./xform/stream-sort")); | ||
__export(require("./xform/take-nth")); | ||
__export(require("./xform/take-while")); | ||
__export(require("./xform/take")); | ||
__export(require("./xform/throttle")); |
{ | ||
"name": "@thi.ng/transducers", | ||
"version": "0.5.3", | ||
"version": "0.6.0", | ||
"description": "Lightweight transducer implementations for ES6 / TypeScript", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
165
README.md
@@ -7,3 +7,3 @@ # @thi.ng/transducers | ||
The library provides 33 transducers and 15 reducers for composing data | ||
The library provides 35 transducers and 15 reducers for composing data | ||
transformation pipelines (more to come). | ||
@@ -21,7 +21,15 @@ | ||
## Usage | ||
## Usage examples | ||
```js | ||
```typescript | ||
// full import | ||
import * as tx from "@thi.ng/transducers"; | ||
// selective | ||
import { transduce } from "@thi.ng/transducers/transduce"; | ||
import { push } from "@thi.ng/transducers/rfn/push"; | ||
import { map } from "@thi.ng/transducers/xforms/map"; | ||
``` | ||
```typescript | ||
xform = tx.comp( | ||
@@ -34,7 +42,7 @@ tx.filter(x => (x & 1) > 0), // odd numbers only | ||
// collect as array (tx.push) | ||
tx.transduce(xform, tx.push, [1, 2, 3, 4, 5, 4, 3, 2, 1]); | ||
tx.transduce(xform, tx.push(), [1, 2, 3, 4, 5, 4, 3, 2, 1]); | ||
// [ 3, 9, 15 ] | ||
// re-use xform, but collect as set (tx.conj) | ||
tx.transduce(xform, tx.conj, [1, 2, 3, 4, 5, 4, 3, 2, 1]); | ||
tx.transduce(xform, tx.conj(), [1, 2, 3, 4, 5, 4, 3, 2, 1]); | ||
// Set { 3, 9, 15 } | ||
@@ -52,2 +60,4 @@ | ||
// use nested reduce to compute window averages | ||
// this combined transducer is also directly | ||
// available as: `tx.movingAverage(n)` | ||
tx.transduce( | ||
@@ -58,3 +68,3 @@ tx.comp( | ||
), | ||
tx.push, | ||
tx.push(), | ||
[1, 2, 3, 3, 4, 5, 5, 6, 7, 8, 8, 9, 10] | ||
@@ -73,3 +83,3 @@ ); | ||
), | ||
tx.push, | ||
tx.push(), | ||
[1, 2, 3, 4] | ||
@@ -88,9 +98,30 @@ ); | ||
tx.transduce(tx.map(x => x.toUpperCase()), tx.frequencies, "hello world") | ||
// 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, "hello world") | ||
// Map { 'h' => 1, 'e' => 1, 'l' => 3, 'o' => 2, ' ' => 1, 'w' => 1, 'r' => 1, 'd' => 1 } | ||
tx.reduce(tx.frequencies(), [1, 1, 1, 2, 3, 4, 4]) | ||
// Map { 1 => 3, 2 => 1, 3 => 1, 4 => 2 } | ||
// CSV parsing | ||
tx.transduce( | ||
tx.comp( | ||
// split into rows | ||
tx.mapcat(x => x.split("\n")), | ||
// split each row | ||
tx.map(x => x.split(",")), | ||
// convert each row into object, rename array indices | ||
tx.rename({ id: 0, name: 1, alias: 2, num: "length" }) | ||
), | ||
tx.push(), | ||
["100,typescript\n101,clojure,clj\n110,rust,rs"] | ||
); | ||
// [ { num: 2, name: 'typescript', id: '100' }, | ||
// { num: 3, alias: 'clj', name: 'clojure', id: '101' }, | ||
// { num: 3, alias: 'rs', name: 'rust', id: '110' } ] | ||
// early termination: | ||
@@ -100,3 +131,3 @@ // result is realized after max. 7 values, irrespective of nesting | ||
tx.comp(tx.flatten(), tx.take(7)), | ||
tx.push, | ||
tx.push(), | ||
[1, [2, [3, 4, [5, 6, [7, 8], 9, [10]]]]] | ||
@@ -106,2 +137,3 @@ ) | ||
// this transducer uses 2 scans (a scan = inner reducer per item) | ||
@@ -120,3 +152,3 @@ // 1) counts incoming values | ||
tx.transduce(xform, tx.push, [1, 1, 1, 1]); | ||
tx.transduce(xform, tx.push(), [1, 1, 1, 1]); | ||
// [ [ [ 1 ] ], | ||
@@ -128,5 +160,6 @@ // [ [ 1 ], [ 2, 2 ] ], | ||
// more simple & similar to previous, but without the 2nd xform step | ||
tx.transduce(tx.comp(tx.scan(tx.count), tx.scan(tx.pushCopy)), tx.push, [1,1,1,1]) | ||
tx.transduce(tx.comp(tx.scan(tx.count), tx.scan(tx.pushCopy)), tx.push(), [1,1,1,1]) | ||
// [ [ 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()); | ||
@@ -153,2 +186,6 @@ f(1); // 1 | ||
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. | ||
```typescript | ||
@@ -184,4 +221,4 @@ interface Reducer<A, B> extends Array<any> { | ||
Currently only `partition`, `partitionBy`, `streamSort`, `streamShuffle` make | ||
use of the 1-arity completing function. | ||
Currently `partition`, `partitionBy`, `streamSort`, `streamShuffle` are the only operators making | ||
use of the 1-arity completing function of their reducer. | ||
@@ -255,65 +292,59 @@ #### Reduced | ||
#### `reduce<A, B>(rfn: Reducer<A, B>, acc: A, xs: Iterable<B>): A` | ||
#### `comp(f1, f2, ...)` | ||
#### `transduce<A, B, C>(tx: Transducer<A, B>, rfn: Reducer<C, B>, acc: C, xs: Iterable<A>): C` | ||
#### `compR(rfn: Reducer<any, any>, fn: (acc, x) => any): Reducer<any, any>` | ||
#### `iterator<A, B>(tx: Transducer<A, B>, xs: Iterable<A>): IterableIterator<B>` | ||
#### `comp(f1, f2, ...)` | ||
#### `juxt(f1, f2, ...)` | ||
#### `compR(rfn: Reducer<any, any>, fn: (acc, x) => any): Reducer<any, any>` | ||
#### `reduce<A, B>(rfn: Reducer<A, B>, acc: A, xs: Iterable<B>): A` | ||
#### `transduce<A, B, C>(tx: Transducer<A, B>, rfn: Reducer<C, B>, acc: C, xs: Iterable<A>): C` | ||
### Transducers | ||
#### `map<A, B>(fn: (x: A) => B): Transducer<A, B>` | ||
#### `benchmark(): Transducer<any, number>` | ||
#### `mapIndexed<A, B>(fn: (i: number, x: A) => B): Transducer<A, B>` | ||
#### `cat<A>(): Transducer<A[], A>` | ||
#### `mapcat<A, B>(fn: (x: A) => Iterable<B>): Transducer<A, B>` | ||
#### `chunkSort<T>(n: number, key?: ((x: T) => any), cmp?: Comparator<any>): Transducer<T, T>` | ||
#### `cat<A>(): Transducer<A[], A>` | ||
#### `dedupe<T>(equiv?: (a: T, b: T) => boolean): Transducer<T, T>` | ||
#### `flatten<T>(): Transducer<T | Iterable<T>, T>` | ||
#### `delayed<T>(t: number): Transducer<T, Promise<T>>` | ||
#### `flattenOnly<T>(pred: Predicate<T>): Transducer<T | Iterable<T>, T>` | ||
#### `distinct<T>(mapfn?: (x: T) => any): Transducer<T, T>` | ||
#### `selectKeys(...keys: PropertyKey[]): Transducer<any, any>` | ||
#### `drop<T>(n: number): Transducer<T, T>` | ||
#### `pluck(key: PropertyKey): Transducer<any, any>` | ||
#### `dropNth<T>(n: number): Transducer<T, T>` | ||
#### `scan<A, B>(rfn: Reducer<B, A>, acc?: B): Transducer<A, B>` | ||
#### `dropWhile<T>(pred: Predicate<T>): Transducer<T, T>` | ||
#### `filter<T>(pred: Predicate<T>): Transducer<T, T>` | ||
#### `keep<T>(f?: ((x: T) => any)): Transducer<T, T>` | ||
#### `flatten<T>(): Transducer<T | Iterable<T>, T>` | ||
#### `throttle<T>(delay: number): Transducer<T, T>` | ||
#### `flattenOnly<T>(pred: Predicate<T>): Transducer<T | Iterable<T>, T>` | ||
#### `delayed<T>(t: number): Transducer<T, Promise<T>>` | ||
#### `bench(): Transducer<any, number>` | ||
#### `sideEffect<T>(fn: (x: T) => void): Transducer<T, T>` | ||
#### `inspect<T>(prefix?: string): Transducer<T, T>` | ||
#### `distinct<T>(mapfn?: (x: T) => any): Transducer<T, T>` | ||
#### `interleave<A, B>(sep: B | (() => B)): Transducer<A, A | B>` | ||
#### `dedupe<T>(equiv?: (a: T, b: T) => boolean): Transducer<T, T>` | ||
#### `interpose<A, B>(sep: B | (() => B)): Transducer<A, A | B>` | ||
#### `interleave<A, B>(sep: B | (() => B)): Transducer<A, A | B>` | ||
#### `keep<T>(f?: ((x: T) => any)): Transducer<T, T>` | ||
#### `take<T>(n: number): Transducer<T, T>` | ||
#### `map<A, B>(fn: (x: A) => B): Transducer<A, B>` | ||
#### `takeWhile<T>(pred: Predicate<T>): Transducer<T, T>` | ||
#### `mapcat<A, B>(fn: (x: A) => Iterable<B>): Transducer<A, B>` | ||
#### `takeNth<T>(n: number): Transducer<T, T>` | ||
#### `mapIndexed<A, B>(fn: (i: number, x: A) => B): Transducer<A, B>` | ||
#### `drop<T>(n: number): Transducer<T, T>` | ||
#### `partition<T>(size: number, step?: number, all?: boolean): Transducer<T, T[]>` | ||
#### `dropWhile<T>(pred: Predicate<T>): Transducer<T, T>` | ||
#### `partitionBy<T>(fn: (x: T) => any): Transducer<T, T[]>` | ||
#### `dropNth<T>(n: number): Transducer<T, T>` | ||
#### `pluck(key: PropertyKey): Transducer<any, any>` | ||
@@ -324,38 +355,48 @@ #### `repeat<T>(n: number): Transducer<T, T>` | ||
#### `partition<T>(size: number, step?: number, all?: boolean): Transducer<T, T[]>` | ||
#### `scan<A, B>(rfn: Reducer<B, A>, acc?: B): Transducer<A, B>` | ||
#### `partitionBy<T>(fn: (x: T) => any): Transducer<T, T[]>` | ||
#### `selectKeys(...keys: PropertyKey[]): Transducer<any, any>` | ||
#### `chunkSort<T>(n: number, key?: ((x: T) => any), cmp?: Comparator<any>): Transducer<T, T>` | ||
#### `sideEffect<T>(fn: (x: T) => void): Transducer<T, T>` | ||
#### `streamShuffle<T>(n: number, maxSwaps?: number): Transducer<T, T>` | ||
#### `streamSort<T>(n: number, key?: ((x: T) => any), cmp?: Comparator<any>): Transducer<T, T>` | ||
#### `streamShuffle<T>(n: number, maxSwaps?: number): Transducer<T, T>` | ||
#### `take<T>(n: number): Transducer<T, T>` | ||
### Reducers | ||
#### `takeNth<T>(n: number): Transducer<T, T>` | ||
#### `push: Reducer<any[], any>` | ||
#### `takeWhile<T>(pred: Predicate<T>): Transducer<T, T>` | ||
#### `pushCopy: Reducer<any[], any>` | ||
#### `throttle<T>(delay: number): Transducer<T, T>` | ||
#### `conj: Reducer<Set<any>, any>` | ||
### Reducers | ||
#### `assocObj: Reducer<any, [PropertyKey, any]>` | ||
#### `add(): Reducer<number, number>` | ||
#### `assocMap: Reducer<Map<any, any>, [any, any]>` | ||
#### `assocMap<A, B>(): Reducer<Map<A, B>, [A, B]>` | ||
#### `add: Reducer<number, number>` | ||
#### `assocObj<T>(): Reducer<IObjectOf<T>, [PropertyKey, T]>` | ||
#### `count: Reducer<number, number>` | ||
#### `conj<T>(): Reducer<Set<T>, T>` | ||
#### `mul: Reducer<number, number>` | ||
#### `count(): Reducer<number, number>` | ||
#### `min: Reducer<number, number>` | ||
#### `frequencies<T>(): Reducer<Map<T, number>, T>` | ||
#### `max: Reducer<number, number>` | ||
#### `last(): last<T>(): Reducer<T, T>` | ||
#### `max(): Reducer<number, number>` | ||
#### `mean(): Reducer<number, number>` | ||
#### `frequencies: Reducer<Map<any, number>, any` | ||
#### `min(): Reducer<number, number>` | ||
#### `mul(): Reducer<number, number>` | ||
#### `push<T>(): Reducer<T[], T>` | ||
#### `pushCopy<T>(): Reducer<T[], T>` | ||
## Authors | ||
@@ -362,0 +403,0 @@ - Karsten Schmidt |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
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
51278
120
1178
393
1