import { primes } from "../projEuler/helpers/primes.ts"; export default class Range implements Iterable { constructor( public iterable: Iterable, ) {} [Symbol.iterator]() { return this.iterable[Symbol.iterator](); } limit(n: number) { const iterable = this.iterable; function* res() { let i = 0; for (const x of iterable) { if (i >= n) { break; } yield x; i++; } } return new Range(res()); } count() { let i = 0; for (const _x of this.iterable) { i++; } return i; } empty() { for (const _x of this.iterable) { return false; } return true; } stringJoin(sep = "") { let iter = this[Symbol.iterator](); const first = iter.next(); if (first.done) { return ""; } let res = String(first.value); for (const x of asIterable(iter)) { res += sep; res += x; } return res; } sum(this: Range) { let res = 0; for (const x of this.iterable) { res += x; } return res; } bigSum(this: Range) { let res = 0n; for (const x of this.iterable) { res += x; } return res; } product(this: Range) { let res = 1; for (const x of this.iterable) { res *= x; } return res; } bigProduct(this: Range) { let res = 1n; for (const x of this.iterable) { res *= x; } return res; } map(fn: (x: T) => MappedT) { const iterable = this.iterable; function* res() { for (const x of iterable) { yield fn(x); } } return new Range(res()); } flatMap(fn: (x: T) => Iterable) { const iterable = this.iterable; function* res() { for (const x of iterable) { for (const y of fn(x)) { yield y; } } } return new Range(res()); } flatten(this: Range>) { const iterable = this.iterable; function* res() { for (const x of iterable) { for (const y of x) { yield y; } } } return new Range(res()); } filter(fn: (x: T) => boolean) { const iterable = this.iterable; function* res() { for (const x of iterable) { if (fn(x)) { yield x; } } } return new Range(res()); } at(n: number) { if (n < 0) { if (n === -1) { return this.last(); } let buf: T[] = []; let len = -n; let i = 0; for (const x of this.iterable) { buf[i % len] = x; i++; } if (buf.length < len) { return undefined; } return buf[i % len]; } let i = 0; for (const x of this.iterable) { if (i === n) { return x; } i++; } } first() { for (const x of this.iterable) { return x; } } last() { let res: T | undefined; for (const x of this.iterable) { res = x; } return res; } indexed() { const iterable = this.iterable; function* res() { let i = 0; for (const x of iterable) { yield [i, x] as [number, T]; i++; } } return new Range(res()); } append(newItems: Iterable) { const iterable = this.iterable; function* res() { yield* iterable; yield* newItems; } return new Range(res()); } prepend(newItems: Iterable) { const iterable = this.iterable; function* res() { yield* newItems; yield* iterable; } return new Range(res()); } zip(other: Iterable) { const iterable = this.iterable; function* res() { let iter1 = iterable[Symbol.iterator](); let iter2 = other[Symbol.iterator](); while (true) { const x1 = iter1.next(); const x2 = iter2.next(); if (x1.done || x2.done) { break; } yield [x1.value, x2.value] as [T, U]; } } return new Range(res()); } skip(n: number) { const iterable = this.iterable; function* res() { let iter = iterable[Symbol.iterator](); for (let i = 0; i < n; i++) { iter.next(); } while (true) { const x = iter.next(); if (x.done) { break; } yield x.value; } } return new Range(res()); } reduce(state: S, fn: (state: S, x: T) => S) { for (const x of this.iterable) { state = fn(state, x); } return state; } while(fn: (x: T) => boolean) { const iterable = this.iterable; function* res() { for (const x of iterable) { if (fn(x)) { yield x; } else { break; } } } return new Range(res()); } window(len: number) { const iterable = this.iterable; function* res() { let iter = iterable[Symbol.iterator](); let memory = []; for (let i = 0; i < len; i++) { const { value, done } = iter.next(); if (done) { return; } memory.push(value); } yield new Range(memory); let i = 0; for (const x of asIterable(iter)) { memory[i] = x; const memoryCopy = memory; const iCopy = i; yield new Range((function* () { for (let j = 1; j <= len; j++) { yield memoryCopy[(iCopy + j) % len]; } })()); i++; i %= len; } } return new Range(res()); } static fromConversion( iter?: Iterable | Iterator | (() => Iterable), ) { if (iter === undefined) { return new Range([]); } if (typeof iter === "function") { return new Range(iter()); } if (Symbol.iterator in iter) { return new Range(iter); } if ("next" in iter) { return Range.fromIterator(iter); } never(iter); } static from(iterable: Iterable = []) { return new Range(iterable); } static fromIterator(iterator: Iterator) { return new Range({ [Symbol.iterator]: () => iterator, }); } static numbers(start = 0, end?: number) { if (end === undefined) { return new Range((function* () { for (let i = start;; i++) { yield i; } })()); } return new Range((function* () { for (let i = start; i < end; i++) { yield i; } })()); } static primes() { return new Range(primes()); } } function never(x: never): never { throw new Error(`Unexpected value: ${x}`); } function asIterable(iterator: Iterator): Iterable { return { [Symbol.iterator]: () => iterator }; }