import { Voidable } from "../maybe" import { OnceIter } from "../onceiter" import { Option } from "../option" import { AnyPair, ArrayGuard } from "../types" export function of(...iter: T[]): Iterable { return iter } export function collect(iter: Iterable): T[] { return [...iter] } export function join(iter: Iterable, separator?: string): string { return [...iter].join(separator) } export function count(iter: Iterable): number { if ('length' in iter) return (iter as any).length if ('size' in iter) return (iter as any).size let i = 0 for (const _ of iter) i++ return i } export function isEmpty(iter: Iterable): boolean { if ('length' in iter) return (iter as any).length == 0 if ('size' in iter) return (iter as any).size == 0 for (const _ of iter) return false return true } export function first(iter: Iterable): Voidable { for (const i of iter) return i } export function firstO(iter: Iterable): Option { for (const i of iter) return Option.some(i) return Option.None } export function last(iter: Iterable): Voidable { if (iter instanceof Array) return iter[iter.length - 1] let r: Voidable for (const i of iter) { r = i } return r } export function lastO(iter: Iterable): Option { if (iter instanceof Array) return iter.length == 0 ? Option.None : Option.some(iter[iter.length - 1]) let r: Voidable, has: boolean = false for (const i of iter) { r = i has = true } return has ? Option.some(r) : Option.None } export function nth(iter: Iterable, n: number): Voidable { if (iter instanceof Array) return iter[n] let i = 0 for (const e of iter) { if (i == n) return e i++ } return } export function nthO(iter: Iterable, n: number): Option { if (iter instanceof Array) return iter.length > n ? Option.some(iter[n]) : Option.None let i = 0 for (const e of iter) { if (i == n) return Option.some(e) i++ } return Option.None } export function* stepBy(iter: Iterable, step: number): Iterable { if (step < 1) step = 1 let i = 0, first = true for (const e of iter) { if (first || i >= step) { yield e i = 1 } else { i++ } first = false } } export function* chain(a: Iterable, b: Iterable, ...more: Iterable[]): Iterable { yield* a yield* b for (const iter of more) { yield* iter } } export function* zip(a: Iterable, b: Iterable): Iterable<[A, B]> { const ai = a[Symbol.iterator]() const bi = b[Symbol.iterator]() for (; ;) { const a = ai.next() if (a.done) return const b = bi.next() if (b.done) return yield [a.value, b.value] } } export function unzip(iter: Iterable<[A, B]>): [A[], B[]] { let [a, b]: [A[], B[]] = [[], []] for (const i of iter) { a.push(i[0]) b.push(i[1]) } return [a, b] } export function* map(iter: Iterable, f: (v: T) => R): Iterable { for (const i of iter) { yield f(i) } } export function* fill(iter: Iterable, v: R): Iterable { for (const _ of iter) { yield v } } export function forEach(iter: Iterable, f: (v: T) => unknown): void { for (const i of iter) { f(i) } } export function run(iter: Iterable): void { for (const _ of iter) { } } export function filter(iter: Iterable, f: (v: T) => v is S): Iterable export function filter(iter: Iterable, f: (v: T) => unknown): Iterable export function* filter(iter: Iterable, f: (v: T) => unknown): Iterable { for (const i of iter) { if (f(i)) yield i } } export function* enumerate(iter: Iterable): Iterable<[T, number]> { let i = 0 for (const e of iter) { yield [e, i] i++ } } export function* indexed(iter: Iterable): Iterable<[number, T]> { let i = 0 for (const e of iter) { yield [i, e] i++ } } export function* skip(iter: Iterable, n: number): Iterable { for (const [e, i] of enumerate(iter)) { if (i >= n) yield e } } export function* take(iter: Iterable, n: number): Iterable { for (const [e, i] of enumerate(iter)) { yield e if (i + 1 >= n) return } } export function* slice(iter: Iterable, from: number, to: number): Iterable { for (const [e, i] of enumerate(iter)) { if (i >= from) yield e if (i + 1 >= to) return } } export function sub(iter: Iterable, from: number, count: number): Iterable { return slice(iter, from, count + from) } export function* scan(iter: Iterable, init: R, f: (acc: R, val: T) => R): Iterable { let acc = init for (const i of iter) { acc = f(acc, i) yield acc } } export function* flatMap(iter: Iterable, f: (v: T) => Iterable): Iterable { for (const i of iter) { yield* f(i) } } export function* flatten(iter: Iterable>): Iterable { for (const i of iter) { yield* i } } export function* also(iter: Iterable, f: (v: T) => void): Iterable { for (const i of iter) { f(i) yield i } } export function fold(a: Iterable, init: R, f: (acc: R, val: T) => R): R { let acc = init for (const i of a) { acc = f(acc, i) } return acc } export function reduce(a: Iterable, f: (acc: T, val: T) => T): T { let acc: T | undefined, first = true for (const i of a) { if (first) (acc = i, first = false) else acc = f(acc!, i) } if (first) throw new TypeError('no item') return acc! } export function all(a: Iterable, f: (v: T) => v is S): a is Iterable export function all(a: Iterable, f: (v: T) => unknown): boolean export function all(a: Iterable, f: (v: T) => unknown): boolean { for (const i of a) { if (!f(i)) return false } return true } export function any(a: Iterable, f: (v: T) => unknown): boolean { for (const i of a) { if (f(i)) return true } return false } export function find(a: Iterable, f: (v: T) => unknown): Voidable { for (const i of a) { if (f(i)) return i } } export function findO(a: Iterable, f: (v: T) => unknown): Option { for (const i of a) { if (f(i)) return Option.some(i) } return Option.None } export function position(a: Iterable, f: (v: T) => unknown): number { for (const [e, i] of enumerate(a)) { if (f(e)) return i } return -1 } export function indexOf(a: Iterable, v: T): number { for (const [e, i] of enumerate(a)) { if (e == v) return i } return -1 } export function includes(a: Iterable, v: T): boolean { for (const i of a) { if (i === v) return true } return false } export function max(a: Iterable): Voidable { let r: Voidable, first = true for (const i of a) { if (first) (r = i, first = false) else if (i > r!) r = i } return r } export function maxO(a: Iterable): Option { let r: Voidable, first = true for (const i of a) { if (first) (r = i, first = false) else if (i > r!) r = i } return first ? Option.None : Option.some(r) } export function min(a: Iterable): Voidable { let r: Voidable, first = true for (const i of a) { if (first) (r = i, first = false) else if (i < r!) r = i } return r } export function minO(a: Iterable): Option { let r: Voidable, first = true for (const i of a) { if (first) (r = i, first = false) else if (i < r!) r = i } return first ? Option.None : Option.some(r) } export function sum(a: Iterable, defv: T): T export function sum(a: Iterable): Voidable export function sum(a: Iterable, defv: Voidable = void 0): Voidable { let r: Voidable = defv, first = true for (const i of a) { if (first) (r = i, first = false) else (r as any) += i as any } return r } export function avg(a: Iterable, defv: T): T export function avg(a: Iterable): Voidable export function avg(a: Iterable, defv: Voidable = void 0): Voidable { let r: Voidable = defv, first = true let count = 0 for (const i of a) { count++ if (first) (r = i, first = false) else (r as any) += i as any } if (count > 0) return ((r as any) / (count as any)) as any return r } export function* push(a: Iterable, ...items: T[]): Iterable { yield* a yield* items } export function* unshift(a: Iterable, ...items: T[]): Iterable { yield* items yield* a } export function as(a: Iterable): Iterable { return a as any } export function toArray(a: Iterable): T[] { if (a instanceof Array) return a return Array.from(a) } export function toSet(a: Iterable): Set { if (a instanceof Set) return a return new Set(a) } export function toMap(a: Iterable<[K, V]>): Map export function toMap(a: Iterable): Map export function toMap(a: Iterable<[K, V] | readonly [K, V]>): Map export function toMap(a: Iterable<[K, V] | readonly [K, V]>): Map { if (a instanceof Map) return a return new Map(a) } /** Cartesian product */ export function product[]>(...iters: O): Iterable ? T : never }>> export function product(...iters: Iterable[]): Iterable export function* product(...iters: Iterable[]): Iterable { if (iters.length == 0) return if (iters.length == 1) { yield* map(iters[0], t => [t]) return } const [iter, ...tailitr] = iters const tail = tailitr.map(i => new OnceIter(i)) function* dopro(i: number, ...parent: T[]): Iterable { if (i < tail.length) { for (const e of tail[i]) { yield* dopro(i + 1, ...parent, e) } } else { yield parent } } for (const e of iter) { yield* dopro(0, e) } } export function groupBy(a: Iterable, keyf: (v: T) => K): Iterable<[K, T[]]> export function groupBy(a: Iterable, keyf: (v: T) => K, valf: (v: T) => V): Iterable<[K, V[]]> export function groupBy(a: Iterable, keyf: (v: T) => K, valf?: (v: T) => V): Iterable<[K, (V | T)[]]> { const groups = new Map() for (const e of a) { const key = keyf(e) const val = valf?.(e) ?? e let group = groups.get(key) if (group == null) groups.set(key, group = []) group.push(val) } return groups } /** sql inner join */ export function relate(outer: Iterable, inner: Iterable, outerKey: (a: O) => K, innerKey: (b: I) => K): Iterable<[O, I]> { return relateMap(outer, inner, outerKey, innerKey, (a, b) => [a, b]) } /** sql inner join */ export function* relateMap(outer: Iterable, inner: Iterable, outerKey: (a: O) => K, innerKey: (b: I) => K, selector: (a: O, b: I) => R): Iterable { const map = new Map() const oitor = outer[Symbol.iterator]() const iitor = inner[Symbol.iterator]() for (; ;) { const or = oitor.next() if (!or.done) { const key = outerKey(or.value) let g = map.get(key) if (g == null) map.set(key, g = { o: [], i: [] }) for (const ie of g.i) { yield selector(or.value, ie) } g.o.push(or.value) } else { for (; ;) { const ir = iitor.next() if (ir.done) return const key = innerKey(ir.value) const g = map.get(key) if (g == null) continue for (const oe of g.o) { yield selector(oe, ir.value) } } } const ir = iitor.next() if (!ir.done) { const key = innerKey(ir.value) let g = map.get(key) if (g == null) map.set(key, g = { o: [], i: [] }) for (const oe of g.o) { yield selector(oe, ir.value) } g.i.push(ir.value) } else { for (; ;) { const or = oitor.next() if (or.done) return const key = outerKey(or.value) const g = map.get(key) if (g == null) continue for (const ie of g.i) { yield selector(or.value, ie) } } } } } export function mapKey(iter: Iterable<[K, V]>, f: (key: K) => R): Iterable<[R, V]> export function mapKey(iter: Iterable, f: (key: K) => R): Iterable<[R, V]> export function mapKey(iter: Iterable>, f: (key: K) => R): Iterable<[R, V]> export function* mapKey(iter: Iterable>, f: (key: K) => R): Iterable<[R, V]> { for (const [k, v] of iter) { yield [f(k), v] } } export function mapValue(iter: Iterable<[K, V]>, f: (val: V) => R): Iterable<[K, R]> export function mapValue(iter: Iterable, f: (val: V) => R): Iterable<[K, R]> export function mapValue(iter: Iterable>, f: (val: V) => R): Iterable<[K, R]> export function* mapValue(iter: Iterable>, f: (val: V) => R): Iterable<[K, R]> { for (const [k, v] of iter) { yield [k, f(v)] } }