UNPKG

@jasmith79/sequable

Version:

Library functions for working with generators

121 lines (120 loc) 4.52 kB
import { toIterator } from "./sequable.mjs"; /** * Partitions the given Iterable, Iterator, or generator function into an * Iterable of Iterables of size n. * * @param n The size of the sub-sequences. **NOTE**: must be finite! This * function maintains an internal buffer of the intermediate results to * force consumption of the supplied iterator. The supplied iterator can * be infinite, but n must be a finite integer number. * @param sequable The Iterable, Iterator, or generator function to chunk. */ export function* partition(n, sequable) { const iter = toIterator(sequable); // We can't just return take(n, sequable) over and over, we need to force // the consumption of the iterable otherwise iterating through the returned // iterables could have surprising results. let srcDone = false; while (!srcDone) { let i = n; const values = []; while (i--) { const { value, done } = iter.next(); srcDone = Boolean(done); if (srcDone) { if (value !== undefined) values.push(value); break; } else { values.push(value); } } if (values.length) yield values; } } /** * Partitions the given Iterable, Iterator, or generator function into two * Iterables that pass and fail the given predicate, respectively. * * **NOTE:** this function maintains an internal cache of results for the * other Iterable when the first iterable is being consumed. When working with * infinite sequences if there is a long enough run of either passing or failing * while the other Iterable is being consumed it is possible to run out of * heap memory. * * For a concrete example, consider a sequence of integers partitioned by * isEven. The sequence has one odd integer followed by 1000 even * integers repeated endlessly. A consumer that tries to take a large number of * odd numbers will grow the cache of even numbers as the odd iterator is * consumed to the point where the allocation eventually fails. * * @param pred The predicate to split the sequence by. * @param sequable The Iterable, Iterator, or generator function to partition. */ export function partitionBy(pred, sequable) { const iter = toIterator(sequable); const lastPassingValues = []; const lastFailingValues = []; let srcDone = false; return [ { *[Symbol.iterator]() { let { value, done } = iter.next(); srcDone = Boolean(done); while (!srcDone) { if (pred(value)) { lastPassingValues.push(value); yield lastPassingValues.shift(); } else { lastFailingValues.push(value); } ({ value, done } = iter.next()); srcDone = Boolean(done); console.log(`value: ${value}, done: ${done}`); } if (value !== undefined) { if (pred(value)) { lastPassingValues.push(value); } else { lastFailingValues.push(value); } } while (lastPassingValues.length) { yield lastPassingValues.shift(); } }, }, { *[Symbol.iterator]() { let { value, done } = iter.next(); srcDone = Boolean(done); while (!srcDone) { if (pred(value)) { lastPassingValues.push(value); } else { lastFailingValues.push(value); yield lastFailingValues.shift(); } ({ value, done } = iter.next()); srcDone = Boolean(done); } if (value !== undefined) { if (pred(value)) { lastPassingValues.push(value); } else { lastFailingValues.push(value); } } while (lastFailingValues.length) { yield lastFailingValues.shift(); } }, }, ]; }