Skip to content

Instantly share code, notes, and snippets.

@MikuroXina
Last active September 4, 2022 02:45
Show Gist options
  • Select an option

  • Save MikuroXina/1273bf7c7dab757cad9de183707beff8 to your computer and use it in GitHub Desktop.

Select an option

Save MikuroXina/1273bf7c7dab757cad9de183707beff8 to your computer and use it in GitHub Desktop.
Utility generator collection.
function* empty<T>(): Generator<T, void> {}
function* once<T>(elem: T): Generator<T, void> {
yield elem;
}
function* onceWith<T>(fn: () => T): Generator<T, void> {
yield fn();
}
function* repeat<T>(elem: T): Generator<T, never> {
while (true) {
yield elem;
}
}
function* repeatWith<T>(fn: () => T): Generator<T, never> {
while (true) {
yield fn();
}
}
function* successors<T>(first: T, succ: (t: T) => T): Generator<T, never> {
while (true) {
yield first;
first = succ(first);
}
}
function* range(start: number, end: number, step: number = 1): Generator<number, void> {
while (start < end) {
yield start;
start += step;
}
}
function* digits(num: number, radix: number): Generator<number, void> {
if (!Number.isInteger(num)) {
throw new Error("num must be an integer");
}
if (!Number.isInteger(radix) || radix <= 0) {
throw new Error("radix must be a positive integer");
}
while (num != 0) {
yield num % radix;
num /= radix;
}
}
function* zip<A, B>(a: Iterable<A>, b: Iterable<B>): Generator<[A, B], void> {
const aIt = a[Symbol.iterator]();
const bIt = b[Symbol.iterator]();
while (true) {
const aNext = aIt.next();
const bNext = bIt.next();
if (aNext.done || bNext.done) {
break;
}
yield [aNext.value, bNext.value];
}
}
function* chain<T>(aIter: Iterable<T>, bIter: Iterable<T>): Generator<T> {
yield* aIter;
yield* bIter;
}
function* cycle<T>(iter: Iterable<T>): Generator<T, void> {
if (iter[Symbol.iterator]().next().done) {
return;
}
while (true) {
yield* iter;
}
}
function* enumerate<T>(iter: Iterable<T>): Generator<[number, T], void> {
let i = 0;
for (const elem : iter) {
yield [i, elem];
i += 1;
}
}
function* skipWhile<T>(iter: Iterable<T>, pred: (t: T) => boolean): Generator<T, void> {
let skipping = true;
for (const elem of iter) {
if (skipping && !pred(elem)) {
skipping = false;
}
if (!skipping) {
yield elem;
}
}
}
function* takeWhile<T>(iter: Iterable<T>, pred: (t: T) => boolean): Generator<T, void> {
for (const elem of iter) {
if (!pred(elem)) {
break;
}
yield elem;
}
}
function* filter<T, U>(iter: Iterable<T>, pred: (t: T) => boolean): Generator<T, void> {
for (const elem of iter) {
if (pred(elem)) {
yield elem;
}
}
}
function* flatten<T>(iter: Iterable<Iterable<T>>): Generator<T, void> {
for (const elemIter of iter) {
for (const elem of elemIter) {
yield elem;
}
}
}
function* map<T, U>(iter: Iterable<T>, fn: (t: T) => U): Generator<U, void> {
for (const elem of iter) {
yield fn(elem);
}
}
function* skip<T>(iter: Iterable<T>, n: number): Generator<T, void> {
if (!Number.isInteger(n) || n < 0) {
throw new Error("n must be a non-negative integer");
}
for (const elem of iter) {
if (n <= 0) {
yield elem;
}
n -= 1;
}
}
function* take<T>(iter: Iterable<T>, n: number): Generator<T, void> {
if (!Number.isInteger(n) || n < 0) {
throw new Error("n must be a non-negative integer");
}
for (const elem of iter) {
if (n <= 0) {
break;
}
yield elem;
n -= 1;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment