@hongminhee/aitertools@0.6.0Built and signed on GitHub ActionsBuilt and signed on GitHub Actions
Built and signed on GitHub Actions
latest
dahlia/aitertoolsWorks with
•JSR Score88%•This package works with Cloudflare Workers, Node.js, Deno, Bun, Browsers




Downloads4/wk
•Published2 years ago (0.6.0)
Well-tested utility functions dealing with async iterables
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215/** * Takes a specified number of elements from the beginning of an async iterable. * * ``` typescript * import { take } from "./take.ts"; * import { count } from "./infinite.ts"; * * const iterable = take(count(0, 5), 3); * for await (const value of iterable) { * console.log(value); * } * ``` * * The above example will print the following 3 lines: * * ~~~ * 0 * 5 * 10 * ~~~ * * If the iterable is shorter than the specified number, the whole elements are * taken. * * ``` typescript * import { take } from "./take.ts"; * * async function* gen() { yield "foo"; yield "bar"; yield "baz"; } * const iterable = take(gen(), 5); * for await (const value of iterable) console.log(value); * ``` * * The above example will print only 3 elements, because `gen()` yields only 3 * elements: * * ~~~ * foo * bar * baz * ~~~ * * @template T The type of the elements in the `source` and the returned async * iterable. * @param source The async iterable to take elements from. It can be either * finite or infinite. * @param count The number of elements to take. * @returns An async iterable that yields the first `count` elements * from the `source` iterable. */ export async function* take<T>( source: Iterable<T> | AsyncIterable<T>, count: number, ): AsyncIterableIterator<T> { let i = 0; for await (const value of source) { if (i++ >= count) break; yield value; } } /** * Takes elements from the beginning of an async iterable as long as a specified * condition is met. If the condition is not met, the iterable stops. * * ``` typescript * import { takeWhile } from "./take.ts"; * import { count } from "./infinite.ts"; * * const iterable = takeWhile(count(0), v => v < 4); * for await (const value of iterable) console.log(value); * ``` * * The above example will print the following 4 lines: * * ~~~ * 0 * 1 * 2 * 3 * ~~~ * * An async `predicate` function also works. The following example will print * the same 4 lines as the previous example: * * ``` typescript * import { takeWhile } from "./take.ts"; * import { count } from "./infinite.ts"; * * const iterable = takeWhile(count(0), v => Promise.resolve(v < 4)); * for await (const value of iterable) console.log(value); * ``` * * A `predicate` function can take an index as well as the value. * * ``` typescript * import { takeWhile } from "./take.ts"; * import { count } from "./infinite.ts"; * * const iterable = takeWhile(count(0, 10), (_, i) => i < 4); * for await (const value of iterable) console.log(value); * ``` * * The above example will print the following 4 lines: * * ~~~ * 0 * 10 * 20 * 30 * ~~~ * * @template T The type of the elements in the `source` and the returned async * iterable. * @param source The async iterable to take elements from. It can be either * finite or infinite. * @param predicate A predicate function to test each source element for * a condition; the second parameter of the function represents * the index of the source element. It can be either * synchronous or asynchronous. * @returns An async iterable that contains elements from the `source` iterable * that occur before the element at which the `predicate` no longer * passes. */ export async function* takeWhile<T>( source: Iterable<T> | AsyncIterable<T>, predicate: (value: T, index: number) => boolean | Promise<boolean>, ): AsyncIterableIterator<T> { let i = 0; for await (const value of source) { let cont = predicate(value, i++); if (cont instanceof Promise) cont = await cont; if (!cont) break; yield value; } } /** * Takes a specified number of elements from the end of an async iterable. * * ``` typescript * import { takeEnd } from "./take.ts"; * import { range } from "./range.ts"; * * const iterable = takeEnd(range(10), 3); * for await (const value of iterable) console.log(value); * ``` * * The above example will print the following 3 lines: * * ~~~ * 7 * 8 * 9 * ~~~ * * If the iterable is shorter than the specified number, the whole elements are * taken. * * ``` typescript * import { takeEnd } from "./take.ts"; * * async function* gen() { yield "foo"; yield "bar"; yield "baz"; } * const iterable = takeEnd(gen(), 5); * for await (const value of iterable) console.log(value); * ``` * * The above example will print only 3 elements, because `gen()` yields only 3 * elements: * * ~~~ * foo * bar * baz * ~~~ * * @template T The type of the elements in the `source` and the returned async * iterable. * @param source The async iterable to take elements from. It can be either * finite or infinite. * @param count The number of elements to take. It must be a finite integer. * @returns An async iterable that yields the last `count` elements * from the `source` iterable. * @throws `RangeError` if `count` is not a finite integer. */ export async function* takeEnd<T>( source: Iterable<T> | AsyncIterable<T>, count: number, ): AsyncIterableIterator<T> { if (!Number.isFinite(count)) throw new RangeError("count must be finite"); else if (!Number.isInteger(count)) { throw new RangeError("count must be integer"); } else if (count < 1) return; if (Array.isArray(source)) { const length = source.length; for (let i = Math.max(0, length - count); i < length; i++) { yield source[i]; } return; } const buffer: T[] = []; let rewindPos = 0; for await (const value of source) { if (buffer.length >= count) { buffer[rewindPos] = value; if (rewindPos >= count - 1) rewindPos = 0; else rewindPos++; } else { buffer.push(value); } } for (let i = rewindPos; i < buffer.length; i++) yield buffer[i]; for (let i = 0; i < rewindPos; i++) yield buffer[i]; }