From e5e6bffe1e55b3245dace830ff81efc1b040873f Mon Sep 17 00:00:00 2001 From: Herve BECHER Date: Mon, 14 Oct 2024 07:38:23 +0200 Subject: [PATCH] sync --- src/async/impl.ts | 71 +++++--- src/async/index.ts | 2 +- src/async/types.ts | 10 +- src/equality-set.ts | 2 +- src/sync/impl.ts | 398 ++++++++++++++------------------------------ src/sync/index.ts | 8 +- src/sync/types.ts | 7 +- src/types.ts | 2 +- src/utils.ts | 2 +- 9 files changed, 193 insertions(+), 309 deletions(-) diff --git a/src/async/impl.ts b/src/async/impl.ts index f6665cb..b24ad2d 100644 --- a/src/async/impl.ts +++ b/src/async/impl.ts @@ -6,10 +6,10 @@ import { getRandomElementAsync } from "../random/index.js"; import { AsyncRandomOptions } from "../random/types.js"; import { selectionSorter } from "../sorting.js"; import { Sequence } from "../sync/types.js"; -import { MaybeAsyncAnyPredicate, MaybeAsyncConverter, MaybeAsyncEquater, MaybeAsyncBiConverter, MaybeAsyncAccumulator, MaybeAsyncComparer, MaybeAsyncAction, MaybePromiseLike, MaybeAsyncGenerator, MaybeAsyncSequence } from "../types.js"; +import { MaybeAsyncAnyPredicate, MaybeAsyncConverter, MaybeAsyncEquater, MaybeAsyncBiConverter, MaybeAsyncAccumulator, MaybeAsyncComparer, MaybeAsyncAction, MaybePromiseLike, MaybeAsyncGenerator, MaybeAsyncSequence, MaybePromise } from "../types.js"; import { strictEquals, identity, operatorCompare, defaultArrayComparer, combineAsyncComparers, asAsyncIterable } from "../utils.js"; import { array, empty, wrap } from "./index.js"; -import { AsyncSequence, GroupedAsyncSequence, OrderedAsyncSequence } from "./types.js"; +import { AsyncSequence, AsyncSequencePipeline, GroupedAsyncSequence, OrderedAsyncSequence } from "./types.js"; export class AsyncSequenceMarker { } @@ -20,7 +20,7 @@ export abstract class BaseAsyncSequence extends AsyncSequenceMarker im abstract iterator(): AsyncIterator; - apply(pipeline: (sequence: AsyncSequence) => TResult): TResult { + apply(pipeline: AsyncSequencePipeline): MaybePromise { return pipeline(this); } @@ -397,7 +397,7 @@ export abstract class BaseAsyncSequence extends AsyncSequenceMarker im let next = await iterator.next(); if (next.done) { - throw new Error("Sequence contains no element.") + throw new Error("Sequence contains no element."); } if (!selector) { @@ -620,15 +620,15 @@ export abstract class BaseAsyncSequence extends AsyncSequenceMarker im return new ReversedAsyncSequence(this); } - chunked(size: number, asArray?: false): AsyncSequence>; - chunked(size: number, asArray: true): AsyncSequence; - chunked(size: number, asArray?: boolean): AsyncSequence> | AsyncSequence { + chunked(size: number): AsyncSequence>; + chunked(size: number, transformer: AsyncSequencePipeline): AsyncSequence; + chunked(size: number, transformer?: AsyncSequencePipeline): AsyncSequence> | AsyncSequence { if (size <= 0) { throw new Error("Chunk size must be positive."); } - const sequence = new ChunkedAsyncSequence(this, size); - return asArray ? sequence : sequence.select(array); + const result = new ChunkedAsyncSequence(this, size); + return transformer ? result.select(transformer) : result; } async random(options?: AsyncRandomOptions | undefined): Promise { @@ -721,10 +721,6 @@ export class DelegatedAsyncSequence extends AsyncSequenceMarker implem return this.#sequence; } - protected set sequence(value: AsyncSequence) { - this.#sequence = value; - } - [Symbol.asyncIterator]() { return this.iterator(); } @@ -733,7 +729,7 @@ export class DelegatedAsyncSequence extends AsyncSequenceMarker implem return this.#sequence.iterator(); } - apply(pipeline: (sequence: AsyncSequence) => TResult) { + apply(pipeline: AsyncSequencePipeline) { return this.#sequence.apply(pipeline); } @@ -978,10 +974,10 @@ export class DelegatedAsyncSequence extends AsyncSequenceMarker implem return this.#sequence.reversed(); } - chunked(size: number, asArray?: false): AsyncSequence>; - chunked(size: number, asArray: true): AsyncSequence; - chunked(size: number, asArray?: any): AsyncSequence> | AsyncSequence { - return this.#sequence.chunked(size, asArray); + chunked(size: number): AsyncSequence>; + chunked(size: number, transformer: AsyncSequencePipeline): AsyncSequence; + chunked(size: number, transformer?: any): any { + return this.#sequence.chunked(size, transformer); } random(options?: AsyncRandomOptions | undefined): Promise { @@ -1186,9 +1182,9 @@ export class WrappedObjectAsync extends BaseAsyncSequence { } export class WrappedArrayAsync extends BaseAsyncSequence { - readonly #array: MaybePromiseLike[]; + readonly #array: ReadonlyArray>; - constructor(array: MaybePromiseLike[]) { + constructor(array: ReadonlyArray>) { super(); this.#array = array; @@ -1694,6 +1690,10 @@ class AppendAsyncSequence extends BaseAsyncSequence { return n < 0 ? -1 : n + 1; } + override async maxCount() { + return await this.#sequence.maxCount() + 1; + } + override async *iterator() { yield* this.#sequence; yield this.#obj; @@ -1716,23 +1716,29 @@ class PrependAsyncSequence extends BaseAsyncSequence { return n < 0 ? -1 : n + 1; } + override async maxCount() { + return await this.#sequence.maxCount() + 1; + } + override async *iterator() { yield this.#obj; yield* this.#sequence; } } -class PeekAsyncSequence extends DelegatedAsyncSequence { +class PeekAsyncSequence extends BaseAsyncSequence { + readonly #sequence: AsyncSequence; readonly #action: MaybeAsyncAction; constructor(sequence: AsyncSequence, action: MaybeAsyncAction) { - super(sequence); + super(); + this.#sequence = sequence; this.#action = action; } override async *iterator() { - for await (const obj of this.sequence) { + for await (const obj of this.#sequence) { await this.#action(obj); yield obj; } @@ -2023,7 +2029,7 @@ class GroupByAsyncSequence extends BaseAsyncSequence extends BaseAsyncSequence { +class ChunkedAsyncSequence extends BaseAsyncSequence> { readonly #sequence: AsyncSequence; readonly #size: number; @@ -2046,13 +2052,13 @@ class ChunkedAsyncSequence extends BaseAsyncSequence { chunk.push(obj); if (chunk.length === this.#size) { - yield chunk; + yield array(chunk); chunk = []; } } if (chunk.length > 0) { - yield chunk; + yield array(chunk); } } } @@ -2179,7 +2185,18 @@ class CacheAsyncSequence extends BaseAsyncSequence { } override async *iterator() { - yield* this.#cache ??= await this.#sequence.toArray(); + if (this.#cache) { + yield* this.#cache; + } else { + const cache = []; + + for await (const e of this.#sequence) { + cache.push(e); + yield e; + } + + this.#cache = cache; + } } } diff --git a/src/async/index.ts b/src/async/index.ts index 75a46ec..a02aaae 100644 --- a/src/async/index.ts +++ b/src/async/index.ts @@ -33,7 +33,7 @@ export function single(obj: MaybePromiseLike): AsyncSequence { return new WrappedObjectAsync(obj); } -export function array(array: MaybePromiseLike[]): AsyncSequence { +export function array(array: ReadonlyArray>): AsyncSequence { return new WrappedArrayAsync(array); } diff --git a/src/async/types.ts b/src/async/types.ts index 9a15884..89c2857 100644 --- a/src/async/types.ts +++ b/src/async/types.ts @@ -1,11 +1,13 @@ import { Collector } from "../collector/types.js"; import { AsyncRandomOptions } from "../random/types.js"; -import { MaybeAsyncAnyPredicate, MaybeAsyncConverter, MaybeAsyncEquater, MaybeAsyncBiConverter, MaybeAsyncAccumulator, MaybeAsyncComparer, MaybeAsyncAction, MaybeAsyncSequence } from "../types.js"; +import { MaybeAsyncAnyPredicate, MaybeAsyncConverter, MaybeAsyncEquater, MaybeAsyncBiConverter, MaybeAsyncAccumulator, MaybeAsyncComparer, MaybeAsyncAction, MaybeAsyncSequence, MaybeAsyncFunction, MaybePromise } from "../types.js"; + +export type AsyncSequencePipeline = MaybeAsyncFunction<(sequence: AsyncSequence) => TResult>; export interface AsyncSequence extends AsyncIterable { iterator(): AsyncIterator; - apply(pipeline: (sequence: AsyncSequence) => TResult): TResult; + apply(pipeline: AsyncSequencePipeline): MaybePromise; count(predicate?: MaybeAsyncAnyPredicate): Promise; nonEnumeratedCount(): Promise; @@ -105,8 +107,8 @@ export interface AsyncSequence extends AsyncIterable { reversed(): AsyncSequence; - chunked(size: number, asArray?: false): AsyncSequence>; - chunked(size: number, asArray: true): AsyncSequence; + chunked(size: number): AsyncSequence>; + chunked(size: number, transformer: AsyncSequencePipeline): AsyncSequence; random(options?: AsyncRandomOptions): Promise; diff --git a/src/equality-set.ts b/src/equality-set.ts index dc58753..3660898 100644 --- a/src/equality-set.ts +++ b/src/equality-set.ts @@ -93,7 +93,7 @@ class CustomEqualitySet implements EqualitySet { } values() { - return this[Symbol.iterator](); + return this.#list.values(); } [Symbol.iterator]() { diff --git a/src/sync/impl.ts b/src/sync/impl.ts index 5190a66..91ada2e 100644 --- a/src/sync/impl.ts +++ b/src/sync/impl.ts @@ -1,5 +1,3 @@ -import util from "util"; - import { BaseAsyncSequence } from "../async/impl.js"; import { AsyncSequence } from "../async/types.js"; import { Collector } from "../collector/types.js"; @@ -11,7 +9,7 @@ import { RandomOptions } from "../random/types.js"; import { AnyPredicate, Converter, FilterPredicate, Equater, BiConverter, Accumulator, Comparer, Action } from "../types.js"; import { strictEquals, identity, operatorCompare, reverseComparer, asIterable, defaultArrayComparer, combineComparers } from "../utils.js"; import { array, empty } from "./index.js"; -import { Sequence, GroupedSequence, OrderedSequence } from "./types.js"; +import { Sequence, GroupedSequence, OrderedSequence, SequencePipeline } from "./types.js"; export class SequenceMarker { } @@ -20,10 +18,6 @@ export abstract class BaseSequence extends SequenceMarker implements S return this.iterator(); } - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return "Sequence {}"; - } - override valueOf() { return this.toJSON(); } @@ -141,19 +135,11 @@ export abstract class BaseSequence extends SequenceMarker implements S return new ConcatSequence(arr); } - count(predicate?: AnyPredicate) { + _countWithPredicate(predicate: AnyPredicate) { let count = 0; - if (predicate) { - for (const element of this) { - if (predicate(element)) { - count++; - } - } - } else { - const iterator = this.iterator(); - - while (!iterator.next().done) { + for (const element of this) { + if (predicate(element)) { count++; } } @@ -161,6 +147,21 @@ export abstract class BaseSequence extends SequenceMarker implements S return count; } + _countWithoutPredicate() { + let count = 0; + const iterator = this.iterator(); + + while (!iterator.next().done) { + count++; + } + + return count; + } + + count(predicate?: AnyPredicate) { + return predicate ? this._countWithPredicate(predicate) : this._countWithoutPredicate(); + } + nonEnumeratedCount() { return -1; } @@ -175,7 +176,7 @@ export abstract class BaseSequence extends SequenceMarker implements S return n >= 0 ? n : Infinity; } - #tryGetFirst(predicate?: AnyPredicate): { found: boolean, element?: TElement | undefined } { + #tryGetFirst(predicate?: AnyPredicate): { found: boolean, element?: TElement | undefined; } { if (predicate) { for (const element of this) { if (predicate(element)) { @@ -217,7 +218,7 @@ export abstract class BaseSequence extends SequenceMarker implements S return result.found ? result.element : def; } - #tryGetLast(predicate?: AnyPredicate): { found: boolean, element?: TElement } { + #tryGetLast(predicate?: AnyPredicate): { found: boolean, element?: TElement; } { let found = false; let result: TElement | undefined = undefined; @@ -257,7 +258,7 @@ export abstract class BaseSequence extends SequenceMarker implements S return result.found ? result.element : def; } - #tryGetSingle(predicate?: AnyPredicate): { found: boolean, element?: TElement, reason?: number } { + #tryGetSingle(predicate?: AnyPredicate): { found: boolean, element?: TElement, reason?: number; } { if (predicate) { let result: { found: boolean; element: TElement; } | undefined = undefined; @@ -405,7 +406,7 @@ export abstract class BaseSequence extends SequenceMarker implements S let next = iterator.next(); if (next.done) { - throw new Error("Sequence contains no element.") + throw new Error("Sequence contains no element."); } if (!selector) { @@ -454,6 +455,58 @@ export abstract class BaseSequence extends SequenceMarker implements S return this.#find(x => x < 0, converter, comparer); } + #findBounds(selector?: Converter, comparer?: Comparer) { + const iterator = this.iterator(); + + let next = iterator.next(); + + if (next.done) { + throw new Error("Sequence contains no element."); + } + + if (!selector) { + selector = identity as Converter; + } + + if (!comparer) { + comparer = operatorCompare; + } + + let minBound = next.value, maxBound = minBound; + let convertedMinBound = selector(minBound), convertedMaxBound = convertedMinBound; + + while (true) { + next = iterator.next(); + + if (next.done) { + break; + } + + const value = next.value; + const convertedValue = selector(value); + + if (comparer(convertedMinBound, convertedValue) > 0) { + minBound = value; + convertedMinBound = convertedValue; + } + + if (comparer(convertedMaxBound, convertedValue) < 0) { + maxBound = value; + convertedMaxBound = convertedValue; + } + } + + return { min: minBound, max: maxBound }; + } + + bounds(comparer?: Comparer) { + return this.#findBounds(undefined, comparer); + } + + boundsBy(converter: Converter, comparer?: Comparer) { + return this.#findBounds(converter, comparer); + } + order(comparer?: Comparer): OrderedSequence { return new OrderSequence(this, false, comparer); } @@ -628,15 +681,15 @@ export abstract class BaseSequence extends SequenceMarker implements S return new ReversedSequence(this); } - chunked(size: number, asArray?: false): Sequence>; - chunked(size: number, asArray: true): Sequence; - chunked(size: number, asArray?: boolean): Sequence> | Sequence { + chunked(size: number): Sequence>; + chunked(size: number, transformer: SequencePipeline): Sequence; + chunked(size: number, transformer?: SequencePipeline): Sequence> | Sequence { if (size <= 0) { throw new Error("Chunk size must be positive."); } - const sequence = new ChunkedSequence(this, size); - return asArray ? sequence : sequence.select(array); + const result = new ChunkedSequence(this, size); + return transformer ? result.select(transformer) : result; } random(options?: RandomOptions) { @@ -729,10 +782,6 @@ export class DelegatedSequence extends SequenceMarker implements Seque return this.iterator(); } - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return inspect(this.#sequence); - } - toJSON() { return this.#sequence.toJSON(); } @@ -869,6 +918,14 @@ export class DelegatedSequence extends SequenceMarker implements Seque return this.#sequence.maxBy(selector, comparer); } + bounds(comparer?: Comparer) { + return this.#sequence.bounds(comparer); + } + + boundsBy(selector: Converter, comparer?: Comparer) { + return this.#sequence.boundsBy(selector, comparer); + } + order(comparer?: Comparer) { return this.#sequence.order(comparer); } @@ -985,10 +1042,10 @@ export class DelegatedSequence extends SequenceMarker implements Seque return this.#sequence.reversed(); } - chunked(size: number, asArray?: false): Sequence>; - chunked(size: number, asArray: true): Sequence; - chunked(size: number, asArray?: any): Sequence> | Sequence { - return this.#sequence.chunked(size, asArray); + chunked(size: number): Sequence>; + chunked(size: number, transformer: SequencePipeline): Sequence; + chunked(size: number, transformer?: any): any { + return this.#sequence.chunked(size, transformer); } random(options?: RandomOptions) { @@ -1045,10 +1102,6 @@ export class GroupedSequenceImpl extends DelegatedSequence extends BaseSequence { } override *iterator() { } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `Empty {}`; - } } export const EMPTY = new EmptySequence(); @@ -1169,10 +1218,6 @@ export class RangeSequence extends BaseSequence { yield i; } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `Range { start: ${inspect(this.#min)}, end: ${inspect(this.#max)}, step: ${inspect(this.#step)} }`; - } } export class BigIntRangeSequence extends BaseSequence { @@ -1205,10 +1250,6 @@ export class BigIntRangeSequence extends BaseSequence { yield i; } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `BigIntRange { start: ${inspect(this.#min)}, end: ${inspect(this.#max)}, step: ${inspect(this.#step)} }`; - } } export class RepeatSequence extends BaseSequence { @@ -1237,10 +1278,6 @@ export class RepeatSequence extends BaseSequence { yield this.#value; } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `Repeat { value: ${inspect(this.#value)}, amount: ${inspect(this.#count)} }`; - } } export class RepeatForeverSequence extends BaseSequence { @@ -1265,10 +1302,6 @@ export class RepeatForeverSequence extends BaseSequence { yield this.#value; } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `RepeatForever { value: ${inspect(this.#value)} }`; - } } export class WrappedObject extends BaseSequence { @@ -1291,10 +1324,6 @@ export class WrappedObject extends BaseSequence { override *iterator() { yield this.#obj; } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `WrappedObject { value: ${inspect(this.#obj)} }`; - } } export class WrappedIterable extends BaseSequence { @@ -1309,13 +1338,9 @@ export class WrappedIterable extends BaseSequence { override iterator() { return this.#iterable[Symbol.iterator](); } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `WrappedIterable { value: ${inspect(this.#iterable)} }`; - } } -export class WrappedReadonlyArray extends BaseSequence { +export class WrappedArray extends BaseSequence { readonly #array: ReadonlyArray; constructor(array: ReadonlyArray) { @@ -1377,24 +1402,6 @@ export class WrappedReadonlyArray extends BaseSequence { } } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `WrappedArray { value: ${inspect(this.#array)} }`; - } -} - -export class WrappedArray extends WrappedReadonlyArray { - constructor(array: T[]) { - super(array); - } - - override asArray() { - return this.array as T[]; - } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `WrappedArray { value: ${inspect(this.array)} }`; - } } export class WrappedArrayLike extends BaseSequence { @@ -1431,10 +1438,6 @@ export class WrappedArrayLike extends BaseSequence { } } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `WrappedArrayLike { value: ${inspect(this.#arrayLike)} }`; - } } export class WrappedSet extends BaseSequence { @@ -1465,10 +1468,6 @@ export class WrappedSet extends BaseSequence { override iterator() { return this.#set.values(); } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `WrappedSet { value: ${inspect(this.#set)} }`; - } } export class WrappedMap extends BaseSequence<[K, V]> { @@ -1503,10 +1502,6 @@ export class WrappedMap extends BaseSequence<[K, V]> { override iterator() { return this.#map.entries(); } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `WrappedMap { value: ${inspect(this.#map)} }`; - } } export class GeneratorSequence extends BaseSequence { @@ -1521,10 +1516,6 @@ export class GeneratorSequence extends BaseSequence { override iterator() { return this.#generator()[Symbol.iterator](); } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `WrappedGenerator { value: ${inspect(this.#generator)} }`; - } } export class FunctionSequence extends BaseSequence { @@ -1549,10 +1540,6 @@ export class FunctionSequence extends BaseSequence { yield this.#f(); } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `WrappedFunction { value: ${inspect(this.#f)} }`; - } } export class ConcatSequence extends BaseSequence { @@ -1605,10 +1592,6 @@ export class ConcatSequence extends BaseSequence { yield* sequence; } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `Concat { sequences: ${inspect(this.#sequences)} }`; - } } class DistinctSequence extends BaseSequence { @@ -1635,10 +1618,6 @@ class DistinctSequence extends BaseSequence { } } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `Distinct { equater: ${inspect(this.#equater)}, sequence: ${inspect(this.#sequence)} }`; - } } class DistinctBySequence extends BaseSequence { @@ -1667,10 +1646,6 @@ class DistinctBySequence extends BaseSequence { } } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `DistinctBy { converter: ${inspect(this.#converter)}, equater: ${inspect(this.#equater)}, sequence: ${inspect(this.#sequence)} }`; - } } class WhereSequence extends BaseSequence { @@ -1695,10 +1670,6 @@ class WhereSequence extends BaseSequence extends BaseSequence { @@ -1717,10 +1688,6 @@ class SelectManySequence extends BaseSequence { yield* this.#converter(obj); } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `SelectMany { converter: ${inspect(this.#converter)}, sequence: ${inspect(this.#sequence)} }`; - } } class IndexedSequence extends BaseSequence<[number, T]> { @@ -1747,10 +1714,6 @@ class IndexedSequence extends BaseSequence<[number, T]> { yield [i++, obj] as [number, T]; } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `Indexed { sequence: ${inspect(this.#sequence)} }`; - } } class SelectSequence extends BaseSequence { @@ -1777,10 +1740,6 @@ class SelectSequence extends BaseSequence { yield this.#converter(obj); } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `Select { converter: ${inspect(this.#converter)}, sequence: ${inspect(this.#sequence)} }`; - } } class SkipWhileSequence extends BaseSequence { @@ -1810,10 +1769,6 @@ class SkipWhileSequence extends BaseSequence { yield* e; } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `SkipWhile { predicate: ${inspect(this.#predicate)}, sequence: ${inspect(this.#sequence)} }`; - } } class SkipLastSequence extends BaseSequence { @@ -1859,10 +1814,6 @@ class SkipLastSequence extends BaseSequence { i = (i + 1) % this.#n; } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `SkipLast { amount: ${inspect(this.#n)}, sequence: ${inspect(this.#sequence)} }`; - } } class SkipSequence extends BaseSequence { @@ -1899,10 +1850,6 @@ class SkipSequence extends BaseSequence { yield* asIterable(iterator); } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `Skip { amount: ${inspect(this.#n)}, sequence: ${inspect(this.#sequence)} }`; - } } class TakeWhileSequence extends BaseSequence { @@ -1929,10 +1876,6 @@ class TakeWhileSequence extends BaseSequence { yield obj; } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `TakeWhile { predicate: ${inspect(this.#predicate)}, sequence: ${inspect(this.#sequence)} }`; - } } class TakeLastSequence extends BaseSequence { @@ -1964,10 +1907,6 @@ class TakeLastSequence extends BaseSequence { yield* queue; } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `TakeLast { amount: ${inspect(this.#n)}, sequence: ${inspect(this.#sequence)} }`; - } } class TakeSequence extends BaseSequence { @@ -2005,20 +1944,12 @@ class TakeSequence extends BaseSequence { i--; } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `Take { amount: ${inspect(this.#n)}, sequence: ${inspect(this.#sequence)} }`; - } } class OrderSequence extends BaseOrderedSequence { constructor(sequence: Sequence, descending: boolean, sorter?: Comparer) { super(sequence, sorter, descending); } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `Order${this.descending ? "Descending" : ""} { sequence: ${inspect(this.sequence)} }`; - } } class OrderBySequence extends BaseOrderedSequence { @@ -2030,10 +1961,6 @@ class OrderBySequence extends BaseOrderedSequence { this.#selector = selector; } - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `OrderBy${this.descending ? "Descending" : ""} { converter: ${inspect(this.#selector)}, sequence: ${inspect(this.sequence)} }`; - } - static #createSorter(selector: Converter, sorter?: Comparer) { const _sorter = sorter ?? defaultArrayComparer; return (a: T, b: T) => _sorter(selector(a), selector(b)); @@ -2044,10 +1971,6 @@ class ThenOrderSequence extends BaseOrderedSequence { constructor(sequence: OrderedSequence, descending: boolean, sorter?: Comparer) { super(sequence, combineComparers(sequence.comparer ?? defaultArrayComparer, sorter ?? defaultArrayComparer), descending); } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `ThenOrder${this.descending ? "Descending" : ""} { sequence: ${inspect(this.sequence)} }`; - } } class ThenOrderBySequence extends BaseOrderedSequence { @@ -2059,10 +1982,6 @@ class ThenOrderBySequence extends BaseOrderedSequence { this.#selector = selector; } - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `ThenOrderBy${this.descending ? "Descending" : ""} { converter: ${inspect(this.#selector)}, sequence: ${inspect(this.sequence)} }`; - } - static #createCombinedSorter(baseSorter: Comparer | undefined, selector: Converter, sorter?: Comparer) { const _baseSorter = baseSorter ?? defaultArrayComparer; const _sorter = sorter ?? defaultArrayComparer; @@ -2094,10 +2013,6 @@ class AppendSequence extends BaseSequence { yield* this.#sequence; yield this.#obj; } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `Append { value: ${inspect(this.#obj)}, sequence: ${inspect(this.#sequence)} }`; - } } class PrependSequence extends BaseSequence { @@ -2124,34 +2039,36 @@ class PrependSequence extends BaseSequence { yield this.#obj; yield* this.#sequence; } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `Prepend { value: ${inspect(this.#obj)}, sequence: ${inspect(this.#sequence)} }`; - } } -class PeekSequence extends DelegatedSequence { +class PeekSequence extends BaseSequence { + readonly #sequence: Sequence; readonly #action: Action; constructor(sequence: Sequence, action: Action) { - super(sequence); + super(); + this.#sequence = sequence; this.#action = action; } + override nonEnumeratedCount() { + return this.#sequence.nonEnumeratedCount(); + } + + override maxCount() { + return this.#sequence.maxCount(); + } + override *iterator() { - for (const obj of this.sequence) { + for (const obj of this.#sequence) { this.#action(obj); yield obj; } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `Prepend { action: ${inspect(this.#action)}, sequence: ${inspect(this.sequence)} }`; - } } -class ZippedSequence extends BaseSequence<[T, U]> { +export class ZippedSequence extends BaseSequence<[T, U]> { readonly #first: Sequence; readonly #second: Sequence; @@ -2188,10 +2105,6 @@ class ZippedSequence extends BaseSequence<[T, U]> { yield [firstNext.value, secondNext.value] as [T, U]; } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `Zip { first: ${inspect(this.#first)}, second: ${inspect(this.#second)} }`; - } } class UnionSequence extends BaseSequence { @@ -2225,10 +2138,6 @@ class UnionSequence extends BaseSequence { } } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `Union { first: ${inspect(this.#first)}, second: ${inspect(this.#second)} }`; - } } class UnionBySequence extends BaseSequence { @@ -2264,10 +2173,6 @@ class UnionBySequence extends BaseSequence { } } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `Zip { converter: ${inspect(this.#selector)}, equater: ${inspect(this.#equater)}, first: ${inspect(this.#first)}, second: ${inspect(this.#second)} }`; - } } class ExceptSequence extends BaseSequence { @@ -2300,10 +2205,6 @@ class ExceptSequence extends BaseSequence { } } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `Except { equater: ${inspect(this.#equater)}, first: ${inspect(this.#first)}, second: ${inspect(this.#second)} }`; - } } class ExceptBySequence extends BaseSequence { @@ -2338,10 +2239,6 @@ class ExceptBySequence extends BaseSequence { } } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `ExceptBy { converter: ${inspect(this.#selector)}, equater: ${inspect(this.#equater)}, first: ${inspect(this.#first)}, second: ${inspect(this.#second)} }`; - } } class IntersectSequence extends BaseSequence { @@ -2374,10 +2271,6 @@ class IntersectSequence extends BaseSequence { } } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `Intersect { equater: ${inspect(this.#equater)}, first: ${inspect(this.#first)}, second: ${inspect(this.#second)} }`; - } } class IntersectBySequence extends BaseSequence { @@ -2412,10 +2305,6 @@ class IntersectBySequence extends BaseSequence { } } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `IntersectBy { converter: ${inspect(this.#selector)}, equater: ${inspect(this.#equater)}, first: ${inspect(this.#first)}, second: ${inspect(this.#second)} }`; - } } class ReversedSequence extends BaseSequence { @@ -2446,10 +2335,6 @@ class ReversedSequence extends BaseSequence { yield buffer.pop()!; } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `Reversed { sequence: ${inspect(this.#sequence)} }`; - } } class GroupBySequence extends BaseSequence> { @@ -2491,13 +2376,9 @@ class GroupBySequence extends BaseSequence extends BaseSequence { +class ChunkedSequence extends BaseSequence> { readonly #sequence: Sequence; readonly #size: number; @@ -2524,19 +2405,15 @@ class ChunkedSequence extends BaseSequence { chunk.push(obj); if (chunk.length === this.#size) { - yield chunk; + yield array(chunk); chunk = []; } } if (chunk.length > 0) { - yield chunk; + yield array(chunk); } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `ChunkedAsArray { size: ${inspect(this.#size, options)} sequence: ${inspect(this.#sequence, options)} }`; - } } class JoinSequence extends BaseSequence { @@ -2579,10 +2456,6 @@ class JoinSequence extends BaseSequence } } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `Join { firstKeySelector: ${inspect(this.#firstKeySelector)}, secondKeySelector: ${inspect(this.#secondKeySelector)}, resultSelector: ${inspect(this.#resultSelector)}, keyEquater: ${inspect(this.#keyEquater)}, first: ${inspect(this.#first)}, second: ${inspect(this.#second)} }`; - } } class GroupJoinSequence extends BaseSequence { @@ -2632,10 +2505,6 @@ class GroupJoinSequence extends BaseSequence extends BaseSequence { @@ -2675,30 +2544,31 @@ class RemoveSequence extends BaseSequence { yield obj; } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `Remove { value: ${inspect(this.#obj)}, all: ${inspect(this.#all)}, equater: ${inspect(this.#equater)} sequence: ${inspect(this.#sequence)} }`; - } } -class CacheSequence extends DelegatedSequence { - #cached = false; +class CacheSequence extends BaseSequence { + readonly #sequence: Sequence; + #cache: T[] | undefined; constructor(sequence: Sequence) { - super(sequence); + super(); + + this.#sequence = sequence; } - override iterator() { - if (!this.#cached) { - this.sequence = array(this.sequence.toArray()); - this.#cached = true; + override *iterator() { + if (this.#cache) { + yield* this.#cache; + } else { + const cache = []; + + for (const e of this.#sequence) { + cache.push(e); + yield e; + } + + this.#cache = cache; } - - return super.iterator(); - } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `Cached { sequence: ${inspect(this.sequence)} }`; } } @@ -2730,10 +2600,6 @@ class PartitionSequence extends BaseSequence> { yield array(partition); } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `Partition { equater: ${inspect(this.#equater)}, sequence: ${inspect(this.#sequence)} }`; - } } class PartitionBySequence extends BaseSequence> { @@ -2767,10 +2633,6 @@ class PartitionBySequence extends BaseSequence yield array(partition); } } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `PartitionBy { converter: ${inspect(this.#selector)}, equater: ${inspect(this.#equater)}, sequence: ${inspect(this.#sequence)} }`; - } } class AwaitedSequence extends BaseAsyncSequence> { @@ -2785,8 +2647,4 @@ class AwaitedSequence extends BaseAsyncSequence> { override async *iterator() { yield* this.#sequence; } - - [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string { - return `Awaited { sequence: ${inspect(this.#sequence)} }`; - } } diff --git a/src/sync/index.ts b/src/sync/index.ts index b96af7c..1d4894f 100644 --- a/src/sync/index.ts +++ b/src/sync/index.ts @@ -1,6 +1,6 @@ import { mathRandom } from "../random/index.js"; import { RandomGenerator } from "../random/types.js"; -import { BigIntRangeSequence, ConcatSequence, SequenceMarker, FunctionSequence, GeneratorSequence, RangeSequence, RepeatSequence, RepeatForeverSequence, WrappedArrayLike, WrappedIterable, WrappedMap, WrappedObject, WrappedSet, WrappedReadonlyArray, EMPTY } from "./impl.js"; +import { BigIntRangeSequence, ConcatSequence, SequenceMarker, FunctionSequence, GeneratorSequence, RangeSequence, RepeatSequence, RepeatForeverSequence, WrappedArrayLike, WrappedIterable, WrappedMap, WrappedObject, WrappedSet, WrappedArray, EMPTY, ZippedSequence } from "./impl.js"; import { Sequence } from "./types.js"; export function wrap(iterable: Iterable): Sequence { @@ -36,7 +36,7 @@ export function single(obj: T): Sequence { } export function array(array: ReadonlyArray): Sequence { - return new WrappedReadonlyArray(array); + return new WrappedArray(array); } export function arrayLike(arrayLike: ArrayLike): Sequence { @@ -142,6 +142,10 @@ export function concat(...sequences: Sequence[]): Sequence { return new ConcatSequence(sequences); } +export function zip(first: Sequence, second: Sequence): Sequence<[T, T]> { + return new ZippedSequence(first, second); +} + export function isSequence(obj: any): obj is Sequence { return obj instanceof SequenceMarker; } diff --git a/src/sync/types.ts b/src/sync/types.ts index 5cde0bb..b3927ce 100644 --- a/src/sync/types.ts +++ b/src/sync/types.ts @@ -66,6 +66,9 @@ export interface Sequence extends Iterable { max(comparer?: Comparer): TElement; maxBy(selector: Converter, comparer?: Comparer): TElement; + bounds(comparer?: Comparer): { min: TElement, max: TElement; }; + boundsBy(selector: Converter, comparer?: Comparer): { min: TElement, max: TElement; }; + order(comparer?: Comparer): OrderedSequence; orderBy(selector: Converter, comparer?: Comparer): OrderedSequence; @@ -111,8 +114,8 @@ export interface Sequence extends Iterable { reversed(): Sequence; - chunked(size: number, asArray?: false): Sequence>; - chunked(size: number, asArray: true): Sequence; + chunked(size: number): Sequence>; + chunked(size: number, transformer: SequencePipeline): Sequence; random(options?: RandomOptions): TElement | undefined; diff --git a/src/types.ts b/src/types.ts index 3dfbd07..79c3b20 100644 --- a/src/types.ts +++ b/src/types.ts @@ -6,7 +6,7 @@ export type AnyPredicate = (obj: T) => unknown; export type FilterPredicate = (obj: TElement) => obj is TFiltered; export type Converter = (obj: TFrom) => TTo; export type BiConverter = (first: TFromFirst, second: TFromSecond) => TTo; -export type Action = (obj: T) => void; +export type Action = (obj: T) => unknown; export type Accumulator = (acc: TAccumulator, obj: TElement) => TAccumulator; export type Comparer = (first: T, second: T) => number; export type Equater = (first: T, second: T) => boolean; diff --git a/src/utils.ts b/src/utils.ts index 016e0c0..e5b239d 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,4 +1,4 @@ -import { Comparer, MaybeAsyncComparer, AsyncComparer, MaybeAsyncIterator } from "./types.js"; +import { Comparer, MaybeAsyncComparer, AsyncComparer } from "./types.js"; export function isDefined(obj: T): obj is NonNullable { return obj !== undefined && obj !== null;