import { Flu } from "../flu" import { Voidable } from "../maybe" import { Option } from "../option" import { AnyPair, Pair, PairKey, PairValue } from "../types" import { SeqLinq } from "./linq" import { all, also, any, avg, chain, collect, count, enumerate, fill, filter, find, findO, first, firstO, flatMap, flatten, fold, forEach, groupBy, includes, indexed, indexOf, isEmpty, join, last, lastO, map, mapKey, mapValue, max, maxO, min, minO, nth, nthO, position, push, reduce, relate, relateMap, run, scan, skip, slice, stepBy, sub, sum, take, toArray, toMap, toSet, unshift, unzip, zip } from "./ops" export * from './ops' export function seq(iter: Iterable): Seq { return new Seq(() => iter) } export class Seq implements Iterable { constructor(public readonly iter: () => Iterable) { } [Symbol.iterator](): Iterator { return this.iter()[Symbol.iterator]() } /** Create empty seq */ static empty(): Seq { return new Seq(function* () { }) } static by(iter: () => Iterable): Seq { return new Seq(iter) } static of(...iter: T[]): Seq { return seq(iter) } /** Create a Seq from a range starting from 0 */ static to(to: number, step: number = 1): Seq { step = Math.abs(step) if (step <= 0) step = 1 return new Seq(function* () { for (let i = 0; i < to; i += step) { yield i } }) } /** Create a Seq from a range */ static range(from: number, to: number, step: number = 1): Seq { step = Math.abs(step) if (step <= 0) step = 1 const inc = from > to ? -step : step return new Seq(function* () { for (let i = from; i < to; i += inc) { yield i } }) } static repeat(v: T, n: number): Seq { return new Seq(function* () { for (let i = 0; i < n; i++) { yield v } }) } linq(): SeqLinq { return new SeqLinq(this.iter) } flu(): Flu { return Flu.from(this.iter()) } toFlu(): T extends infer R | Promise ? Flu : never { return Flu.fromIter(this as any) as any } collect(): T[] { return collect(this.iter()) } join(separator?: string): string { return join(this.iter(), separator) } count(): number { return count(this.iter()) } isEmpty(): boolean { return isEmpty(this.iter()) } first(): Voidable { return first(this.iter()) } firstO(): Option { return firstO(this.iter()) } last(): Voidable { return last(this.iter()) } lastO(): Option { return lastO(this.iter()) } nth(n: number): Voidable { return nth(this.iter(), n) } nthO(n: number): Option { return nthO(this.iter(), n) } stepBy(step: number): Seq { return new Seq(() => stepBy(this, step)) } chain(other: Iterable, ...more: Iterable[]): Seq { return new Seq(() => chain(this, other, ...more)) } zip(other: Iterable): Seq<[T, U]> { return new Seq(() => zip(this, other)) } unzip(): [ (T extends [infer A, any] | readonly [infer A, any] | (infer A)[] ? A : unknown)[], (T extends [any, infer B] | readonly [any, infer B] | (infer B)[] ? B : unknown)[], ] unzip(): any { return unzip(this.iter() as any) as any } map(f: (v: T) => R): Seq { return new Seq(() => map(this, f)) } fill(v: R): Seq { return new Seq(() => fill(this, v)) } forEach(f: (v: T) => unknown): void { return forEach(this.iter(), f) } run(): void { return run(this.iter()) } filter(f: (v: T) => v is S): Seq filter(f: (v: T) => unknown): Seq filter(f: (v: T) => unknown): Seq { return new Seq(() => filter(this, f)) } enumerate(): Seq<[T, number]> { return new Seq(() => enumerate(this)) } indexed(): Seq<[number, T]> { return new Seq(() => indexed(this)) } skip(n: number): Seq { return new Seq(() => skip(this, n)) } take(n: number): Seq { return new Seq(() => take(this, n)) } slice(from: number, to: number): Seq { return new Seq(() => slice(this, from, to)) } sub(from: number, count: number): Seq { return new Seq(() => sub(this, from, count)) } scan(init: R, f: (acc: R, val: T) => R): Seq { return new Seq(() => scan(this, init, f)) } flatMap(f: (v: T) => Iterable): Seq { return new Seq(() => flatMap(this, f)) } flatten(): T extends Iterable ? Seq : never { return new Seq(() => flatten(this as any)) as any } also(f: (v: T) => void): Seq { return new Seq(() => also(this, f)) } fold(init: R, f: (acc: R, val: T) => R): R { return fold(this.iter(), init, f) } reduce(f: (acc: T, val: T) => T): T { return reduce(this.iter(), f) } all(f: (v: T) => v is S): this is Seq all(f: (v: T) => unknown): boolean all(f: (v: T) => unknown): boolean { return all(this, f) } any(f: (v: T) => unknown): boolean { return any(this.iter(), f) } find(f: (v: T) => unknown): Voidable { return find(this.iter(), f) } findO(f: (v: T) => unknown): Option { return findO(this.iter(), f) } position(f: (v: T) => unknown): number { return position(this.iter(), f) } indexOf(v: T): number { return indexOf(this.iter(), v) } includes(v: T): boolean { return includes(this.iter(), v) } max(): Voidable { return max(this.iter()) } maxO(): Option { return maxO(this.iter()) } min(): Voidable { return min(this.iter()) } minO(): Option { return minO(this.iter()) } sum(defv: T): T extends number | bigint | string ? T : never sum(): T extends number | bigint | string ? Voidable : never sum(defv: Voidable = void 0): T extends number | bigint | string ? Voidable : never { return sum(this.iter() as any, defv as any) as any } avg(defv: T): T extends number | bigint ? T : never avg(): T extends number | bigint ? Voidable : never avg(defv: Voidable = void 0): T extends number | bigint ? Voidable : never { return avg(this.iter() as any, defv as any) as any } push(...items: T[]): Seq { return new Seq(() => push(this, ...items)) } unshift(...items: T[]): Seq { return new Seq(() => unshift(this, ...items)) } as(): Seq { return this as any } toArray(): T[] { return toArray(this.iter()) } toSet(): Set { return toSet(this.iter()) } toMap(): T extends AnyPair ? Map : never { return toMap(this.iter() as any) as any } groupBy(keyf: (v: T) => K): Seq<[K, T[]]> groupBy(keyf: (v: T) => K, valf: (v: T) => V): Seq<[K, V[]]> groupBy(keyf: (v: T) => K, valf?: (v: T) => V): Seq<[K, (T | V)[]]> { return new Seq(() => groupBy(this, keyf, valf!)) } relate(inner: Iterable, outerKey: (a: T) => K, innerKey: (b: I) => K): Seq<[T, I]> { return new Seq(() => relate(this, inner, outerKey, innerKey)) } relateMap(inner: Iterable, outerKey: (a: T) => K, innerKey: (b: I) => K, selector: (a: T, b: I) => R): Seq { return new Seq(() => relateMap(this, inner, outerKey, innerKey, selector)) } get arr() { return this.toArray() } mapKey(f: (key: PairKey) => R): T extends AnyPair ? Seq> : never { return new Seq(() => mapKey(this as any, f)) as any } mapValue(f: (key: PairValue) => R): T extends AnyPair ? Seq> : never { return new Seq(() => mapValue(this as any, f)) as any } }