import { BaseAsyncSequence } from "../async/impl.js"; import { AsyncSequence } from "../async/types.js"; import { Collector } from "../collector/types.js"; import { asComparer, combineComparers, createComparerUsing, defaultComparer } from "../comparer/sync.js"; import { ComparisonOrComparer, Comparer } from "../comparer/types.js"; import { asEqualityComparer, defaultEqualityComparer } from "../equality-comparer/sync.js"; import { EqualityComparer, EqualityComparisonOrComparer } from "../equality-comparer/types.js"; import { createEqualityMap } from "../equality-map/index.js"; import { createEqualitySet } from "../equality-set/index.js"; import { createQueue } from "../queue.js"; import { getRandomElement } from "../random/index.js"; import { RandomOptions } from "../random/types.js"; import { AnyPredicate, Converter, TypePredicate, BiConverter, Accumulator, Action } from "../types.js"; import { FindElementResult, identity } from "../utils.js"; import { array, empty, wrap } from "./index.js"; import { Sequence, GroupedSequence, OrderedSequence, SequencePipeline } from "./types.js"; export class SequenceMarker { } export abstract class BaseSequence extends SequenceMarker implements Sequence { [Symbol.iterator]() { return this.iterator(); } override valueOf() { return this.toJSON(); } toJSON() { return this.asArray(); } abstract iterator(): Iterator; apply(pipeline: (sequence: this) => TResult) { return pipeline(this); } select(converter: Converter): Sequence { return new SelectSequence(this, converter); } selectMany(converter: Converter>): Sequence { return new SelectManySequence(this, converter); } where(predicate: TypePredicate): Sequence; where(predicate: AnyPredicate): Sequence; where(predicate: any) { return new WhereSequence(this, predicate); } groupBy(keySelector: Converter, elementSelector?: Converter, keyComparer?: EqualityComparisonOrComparer): Sequence> { return new GroupBySequence(this, keySelector, elementSelector, keyComparer); } join(sequence: Iterable, firstKeySelector: Converter, secondKeySelector: Converter, resultSelector?: BiConverter, keyComparer?: EqualityComparisonOrComparer): Sequence { return new JoinSequence(this, wrap(sequence), firstKeySelector, secondKeySelector, resultSelector, keyComparer); } groupJoin(sequence: Iterable, firstKeySelector: Converter, secondKeySelector: Converter, resultSelector?: BiConverter, TResult>, keyComparer?: EqualityComparisonOrComparer): Sequence { return new GroupJoinSequence(this, wrap(sequence), firstKeySelector, secondKeySelector, resultSelector, keyComparer); } contains(obj: TElement, equater?: EqualityComparisonOrComparer) { equater = equater ? asEqualityComparer(equater) : defaultEqualityComparer; for (const element of this) { if (equater.equals(element, obj)) { return true; } } return false; } sequenceEquals(sequence: Iterable, equater?: EqualityComparisonOrComparer) { if (this === sequence) { return true; } const other = wrap(sequence); const thisCount = this.nonEnumeratedCount(); const thatCount = other.nonEnumeratedCount(); if (thisCount >= 0 && thatCount >= 0 && thisCount !== thatCount) { return false; } equater = equater ? asEqualityComparer(equater) : defaultEqualityComparer; const thisIterator = this.iterator(); const thatIterator = other.iterator(); while (true) { const thisNext = thisIterator.next(); const thatNext = thatIterator.next(); if (thisNext.done) { return thatNext.done === true; } if (thatNext.done) { return false; } if (!equater.equals(thisNext.value, thatNext.value)) { return false; } } } append(obj: TElement): Sequence { return new AppendSequence(this, obj); } prepend(obj: TElement): Sequence { return new PrependSequence(this, obj); } remove(obj: TElement, all?: boolean, equater?: EqualityComparisonOrComparer): Sequence { return new RemoveSequence(this, obj, all, equater); } concat(...sequences: Iterable[]) { if (sequences.length === 0) { return this; } const arr: Sequence[] = [this]; for (const sequence of sequences) { arr.push(wrap(sequence)); } return new ConcatSequence(arr); } _countWithPredicate(predicate: AnyPredicate) { let count = 0; for (const element of this) { if (predicate(element)) { count++; } } 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; } fastCount() { const n = this.nonEnumeratedCount(); return n >= 0 ? n : this.count(); } maxCount() { const n = this.nonEnumeratedCount(); return n >= 0 ? n : Infinity; } #tryGetFirst(predicate?: AnyPredicate): FindElementResult { if (predicate) { for (const element of this) { if (predicate(element)) { return { found: true, element }; } } } else { const next = this.iterator().next(); if (!next.done) { return { found: true, element: next.value }; } } return { found: false }; } first(predicate?: AnyPredicate) { const result = this.#tryGetFirst(predicate); if (result.found) { return result.element; } throw new Error("No element was found."); } firstOrDefault(predicate?: AnyPredicate, def?: TElement) { const result = this.#tryGetFirst(predicate); return result.found ? result.element : def; } #tryGetLast(predicate?: AnyPredicate): FindElementResult { let result: FindElementResult = { found: false }; if (predicate) { for (const element of this) { if (predicate(element)) { result = { found: true, element }; } } } else { for (const element of this) { result = { found: true, element }; } } return result; } last(predicate?: AnyPredicate) { const result = this.#tryGetLast(predicate); if (result.found) { return result.element; } throw new Error("No element was found."); } lastOrDefault(predicate?: AnyPredicate, def?: TElement) { const result = this.#tryGetLast(predicate); return result.found ? result.element : def; } #tryGetSingle(predicate?: AnyPredicate): FindElementResult { if (predicate) { let result: FindElementResult | undefined = undefined; for (const element of this) { if (predicate(element)) { if (result) { return { found: false, reason: 2 }; } result = { found: true, element }; } } } else { const iterator = this.iterator(); let next = iterator.next(); if (!next.done) { const result: FindElementResult = { found: true, element: next.value }; next = iterator.next(); if (next.done) { return result; } return { found: false, reason: 2 }; } } return { found: false, reason: 1 }; } single(predicate?: AnyPredicate) { const result = this.#tryGetSingle(predicate); if (result.found) { return result.element; } let reason: string; switch (result.reason) { case 1: reason = "No element was found."; break; case 2: reason = "More than one element was found."; break; default: reason = ""; } throw new Error(reason); } singleOrDefault(predicate?: AnyPredicate, def?: TElement) { const result = this.#tryGetSingle(predicate); return result.found ? result.element : def; } #tryElementAt(index: number): FindElementResult { let i = index; for (const element of this) { if (i === 0) { return { found: true, element }; } i--; } return { found: false }; } elementAt(index: number) { const result = this.#tryElementAt(index); if (result.found) { return result.element; } throw new Error("No element found at given index."); } elementAtOrDefault(index: number, def?: TElement) { const result = this.#tryElementAt(index); return result.found ? result.element : def; } aggregate(accumulator: Accumulator, seed?: TAccumulator, resultSelector?: Converter) { const iterator = this.iterator(); if (seed === undefined) { const next = iterator.next(); if (next.done) { throw new Error("Aggregation requires at least one element."); } seed = next.value as unknown as TAccumulator; } let acc = seed; while (true) { const next = iterator.next(); if (next.done) { break; } acc = accumulator(acc, next.value); } if (resultSelector) { return resultSelector(acc); } return acc as unknown as TResult; } #find(sorter: AnyPredicate, selector?: Converter, comparer?: ComparisonOrComparer) { const iterator = this.iterator(); let next = iterator.next(); if (next.done) { throw new Error("Sequence contains no element."); } if (!selector) { selector = identity as Converter; } comparer = comparer ? asComparer(comparer) : defaultComparer; let result = next.value; let convertedResult = selector(result); while (true) { next = iterator.next(); if (next.done) { break; } const value = next.value; const convertedValue = selector(value); if (sorter(comparer.compare(convertedResult, convertedValue))) { result = value; convertedResult = convertedValue; } } return result; } min(comparer?: ComparisonOrComparer) { return this.#find(x => x > 0, undefined, comparer); } minBy(converter: Converter, comparer?: ComparisonOrComparer) { return this.#find(x => x > 0, converter, comparer); } max(comparer?: ComparisonOrComparer) { return this.#find(x => x < 0, undefined, comparer); } maxBy(converter: Converter, comparer?: ComparisonOrComparer) { return this.#find(x => x < 0, converter, comparer); } #findBounds(selector?: Converter, comparer?: ComparisonOrComparer): [min: TElement, max: TElement] { const iterator = this.iterator(); let next = iterator.next(); if (next.done) { throw new Error("Sequence contains no element."); } if (!selector) { selector = identity as Converter; } comparer = comparer ? asComparer(comparer) : defaultComparer; 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.compare(convertedMinBound, convertedValue) > 0) { minBound = value; convertedMinBound = convertedValue; } if (comparer.compare(convertedMaxBound, convertedValue) < 0) { maxBound = value; convertedMaxBound = convertedValue; } } return [minBound, maxBound]; } bounds(comparer?: ComparisonOrComparer) { return this.#findBounds(undefined, comparer); } boundsBy(converter: Converter, comparer?: ComparisonOrComparer) { return this.#findBounds(converter, comparer); } order(comparer?: ComparisonOrComparer): OrderedSequence { return new OrderSequence(this, false, comparer); } orderBy(selector: Converter, comparer?: ComparisonOrComparer): OrderedSequence { return new OrderBySequence(this, false, selector, comparer); } orderDescending(comparer?: ComparisonOrComparer): OrderedSequence { return new OrderSequence(this, true, comparer); } orderByDescending(selector: Converter, comparer?: ComparisonOrComparer): OrderedSequence { return new OrderBySequence(this, true, selector, comparer); } partition(equater?: EqualityComparisonOrComparer): Sequence> { return new PartitionSequence(this, equater); } partitionBy(selector: Converter, equater?: EqualityComparisonOrComparer): Sequence> { return new PartitionBySequence(this, selector, equater); } distinct(equater?: EqualityComparisonOrComparer): Sequence { return new DistinctSequence(this, equater); } distinctBy(selector: Converter, equater?: EqualityComparisonOrComparer): Sequence { return new DistinctBySequence(this, selector, equater); } union(sequence: Iterable, equater?: EqualityComparisonOrComparer): Sequence { return new UnionSequence(this, wrap(sequence), equater); } unionBy(sequence: Iterable, selector: Converter, equater?: EqualityComparisonOrComparer): Sequence { return new UnionBySequence(this, wrap(sequence), selector, equater); } except(sequence: Iterable): Sequence { return new ExceptSequence(this, wrap(sequence)); } exceptBy(sequence: Iterable, selector: Converter): Sequence { return new ExceptBySequence(this, wrap(sequence), selector); } intersect(sequence: Iterable): Sequence { return new IntersectSequence(this, wrap(sequence)); } intersectBy(sequence: Iterable, selector: Converter): Sequence { return new IntersectBySequence(this, wrap(sequence), selector); } all(predicate: AnyPredicate) { const n = this.nonEnumeratedCount(); if (n === 0) { return false; } for (const element of this) { if (!predicate(element)) { return false; } } return true; } any(predicate?: AnyPredicate) { const n = this.nonEnumeratedCount(); if (n === 0) { return false; } if (predicate) { for (const element of this) { if (predicate(element)) { return true; } } return false; } return n < 0 ? !this.iterator().next().done : n > 0; } none(predicate?: AnyPredicate) { const n = this.nonEnumeratedCount(); if (n === 0) { return true; } if (predicate) { for (const element of this) { if (predicate(element)) { return false; } } return true; } return n < 0 && this.iterator().next().done === true; } skip(n: number): Sequence { if (n < 0) { throw new Error("Cannot skip a negative number of elements."); } return n === 0 ? this : new SkipSequence(this, n); } skipLast(n: number): Sequence { if (n < 0) { throw new Error("Cannot skip a negative number of elements."); } return n === 0 ? this : new SkipLastSequence(this, n); } skipWhile(predicate: AnyPredicate): Sequence { return new SkipWhileSequence(this, predicate); } take(n: number): Sequence { if (n < 0) { throw new Error("Cannot take a negative number of elements."); } return n === 0 ? empty() : new TakeSequence(this, n); } takeLast(n: number): Sequence { if (n < 0) { throw new Error("Cannot take a negative number of elements."); } return n === 0 ? empty() : new TakeLastSequence(this, n); } takeWhile(predicate: AnyPredicate): Sequence { return new TakeWhileSequence(this, predicate); } peek(action: Action): Sequence { return new PeekSequence(this, action); } forEach(action: Action) { for (const element of this) { action(element); } } zip(sequence: Iterable): Sequence<[TElement, TOther]> { return new ZippedSequence(this, wrap(sequence)); } cartesianProduct(sequence: Iterable): Sequence<[TElement, TOther]> { return new CartesianProductSequence(this, wrap(sequence)); } indexed(): Sequence<[number, TElement]> { return new IndexedSequence(this); } reversed(): Sequence { return new ReversedSequence(this); } chunked(size: number): Sequence>; chunked(size: number, asArray: true): Sequence; chunked(size: number, transformer: SequencePipeline): Sequence; chunked(size: number, transformerOrAsArray?: true | SequencePipeline): Sequence> | Sequence | Sequence { if (size <= 0) { throw new Error("Chunk size must be positive."); } if (transformerOrAsArray === true) { return new ChunkedArraySequence(this, size); } const result = new ChunkedSequence(this, size); return transformerOrAsArray ? result.select(transformerOrAsArray) : result; } random(options?: RandomOptions) { return getRandomElement(this, options).element; } cached(): Sequence { return new CacheSequence(this); } awaited(): AsyncSequence> { return new AwaitedSequence(this); } asArray() { return this.toArray(); } toArray() { return Array.from(this); } toMap(keySelector: Converter): Map; toMap(keySelector: Converter, valueSelector: Converter): Map; toMap(keySelector: Converter, valueSelector?: Converter): Map { valueSelector ??= identity; const map = new Map(); for (const element of this) { const key = keySelector(element); const value = valueSelector(element); map.set(key, value); } return map; } toSet() { return new Set(this); } toObject(keySelector: Converter): Record; toObject(keySelector: Converter, valueSelector: Converter): Record; toObject(keySelector: Converter, valueSelector?: Converter): Record { valueSelector ??= identity; const obj: Record = {}; for (const element of this) { const key = keySelector(element); const value = valueSelector(element); obj[key] = value; } return obj; } collect(collector: Collector) { const acc = collector.initialize(); for (const e of this) { collector.accumulate(acc, e); } return collector.finalize(acc); } } export class DelegatedSequence extends SequenceMarker implements Sequence { #sequence: Sequence; constructor(sequence: Sequence) { super(); this.#sequence = sequence; } get sequence() { return this.#sequence; } protected set sequence(value: Sequence) { this.#sequence = value; } [Symbol.iterator]() { return this.iterator(); } toJSON() { return this.#sequence.toJSON(); } iterator() { return this.#sequence.iterator(); } apply(pipeline: (sequence: Sequence) => TResult) { return this.#sequence.apply(pipeline); } count(predicate?: AnyPredicate) { return this.#sequence.count(predicate); } nonEnumeratedCount() { return this.#sequence.nonEnumeratedCount(); } fastCount() { return this.#sequence.fastCount(); } maxCount() { return this.#sequence.maxCount(); } select(selector: Converter) { return this.#sequence.select(selector); } selectMany(selector: Converter>) { return this.#sequence.selectMany(selector); } where(predicate: TypePredicate): Sequence; where(predicate: AnyPredicate): Sequence; where(predicate: any): Sequence { return this.#sequence.where(predicate); } groupBy(keySelector: Converter, elementSelector?: undefined, keyComparer?: EqualityComparisonOrComparer | undefined): Sequence>; groupBy(keySelector: Converter, elementSelector: Converter, keyComparer?: EqualityComparisonOrComparer | undefined): Sequence>; groupBy(keySelector: any, elementSelector?: any, keyComparer?: any) { return this.#sequence.groupBy(keySelector, elementSelector, keyComparer); } join(sequence: Iterable, firstKeySelector: Converter, secondKeySelector: Converter, resultSelector?: undefined, keyComparer?: EqualityComparisonOrComparer | undefined): Sequence<[TElement, TOther]>; join(sequence: Iterable, firstKeySelector: Converter, secondKeySelector: Converter, resultSelector: BiConverter, keyComparer?: EqualityComparisonOrComparer | undefined): Sequence; join(sequence: any, firstKeySelector: any, secondKeySelector: any, resultSelector?: any, keyComparer?: any) { return this.#sequence.join(sequence, firstKeySelector, secondKeySelector, resultSelector, keyComparer); } groupJoin(sequence: Iterable, firstKeySelector: Converter, secondKeySelector: Converter, resultSelector?: undefined, keyComparer?: EqualityComparisonOrComparer | undefined): Sequence>; groupJoin(sequence: Iterable, firstKeySelector: Converter, secondKeySelector: Converter, resultSelector: BiConverter, TResult>, keyComparer?: EqualityComparisonOrComparer | undefined): Sequence; groupJoin(sequence: any, firstKeySelector: any, secondKeySelector: any, resultSelector?: any, keyComparer?: any) { return this.#sequence.groupJoin(sequence, firstKeySelector, secondKeySelector, resultSelector, keyComparer); } contains(obj: TElement, equater?: EqualityComparisonOrComparer) { return this.#sequence.contains(obj, equater); } sequenceEquals(sequence: Iterable, equater?: EqualityComparisonOrComparer) { return this.#sequence.sequenceEquals(sequence, equater); } append(obj: TElement) { return this.#sequence.append(obj); } prepend(obj: TElement) { return this.#sequence.prepend(obj); } remove(obj: TElement, all?: boolean, equater?: EqualityComparisonOrComparer) { return this.#sequence.remove(obj, all, equater); } concat(...sequences: Iterable[]) { return this.#sequence.concat(...sequences); } first(predicate?: AnyPredicate) { return this.#sequence.first(predicate); } firstOrDefault(predicate?: AnyPredicate, def?: TElement) { return this.#sequence.firstOrDefault(predicate, def); } last(predicate?: AnyPredicate) { return this.#sequence.last(predicate); } lastOrDefault(predicate?: AnyPredicate, def?: TElement) { return this.#sequence.lastOrDefault(predicate, def); } single(predicate?: AnyPredicate) { return this.#sequence.single(predicate); } singleOrDefault(predicate?: AnyPredicate, def?: TElement) { return this.#sequence.singleOrDefault(predicate, def); } elementAt(index: number) { return this.#sequence.elementAt(index); } elementAtOrDefault(index: number, def?: TElement) { return this.#sequence.elementAtOrDefault(index, def); } aggregate(accumulator: Accumulator, seed?: TAccumulator, resultSelector?: Converter) { return this.#sequence.aggregate(accumulator, seed, resultSelector); } min(comparer?: ComparisonOrComparer) { return this.#sequence.min(comparer); } minBy(selector: Converter, comparer?: ComparisonOrComparer) { return this.#sequence.minBy(selector, comparer); } max(comparer?: ComparisonOrComparer) { return this.#sequence.max(comparer); } maxBy(selector: Converter, comparer?: ComparisonOrComparer) { return this.#sequence.maxBy(selector, comparer); } bounds(comparer?: ComparisonOrComparer) { return this.#sequence.bounds(comparer); } boundsBy(selector: Converter, comparer?: ComparisonOrComparer) { return this.#sequence.boundsBy(selector, comparer); } order(comparer?: ComparisonOrComparer) { return this.#sequence.order(comparer); } orderBy(selector: Converter, comparer?: ComparisonOrComparer) { return this.#sequence.orderBy(selector, comparer); } orderDescending(comparer?: ComparisonOrComparer) { return this.#sequence.orderDescending(comparer); } orderByDescending(selector: Converter, comparer?: ComparisonOrComparer) { return this.#sequence.orderByDescending(selector, comparer); } partition(equater?: EqualityComparisonOrComparer | undefined): Sequence> { return this.#sequence.partition(equater); } partitionBy(selector: Converter, equater?: EqualityComparisonOrComparer | undefined): Sequence> { return this.#sequence.partitionBy(selector, equater); } distinct(equater?: EqualityComparisonOrComparer) { return this.#sequence.distinct(equater); } distinctBy(selector: Converter, equater?: EqualityComparisonOrComparer) { return this.#sequence.distinctBy(selector, equater); } union(sequence: Iterable, equater?: EqualityComparisonOrComparer) { return this.#sequence.union(sequence, equater); } unionBy(sequence: Iterable, selector: Converter, equater?: EqualityComparisonOrComparer) { return this.#sequence.unionBy(sequence, selector, equater); } except(sequence: Iterable, equater?: EqualityComparisonOrComparer) { return this.#sequence.except(sequence, equater); } exceptBy(sequence: Iterable, selector: Converter, equater?: EqualityComparisonOrComparer) { return this.#sequence.exceptBy(sequence, selector, equater); } intersect(sequence: Iterable, equater?: EqualityComparisonOrComparer) { return this.#sequence.intersect(sequence, equater); } intersectBy(sequence: Iterable, selector: Converter, equater?: EqualityComparisonOrComparer) { return this.#sequence.intersectBy(sequence, selector, equater); } all(predicate: AnyPredicate) { return this.#sequence.all(predicate); } any(predicate: AnyPredicate): boolean; any(): boolean; any(predicate?: any) { return this.#sequence.any(predicate); } none(predicate: AnyPredicate): boolean; none(): boolean; none(predicate?: any) { return this.#sequence.none(predicate); } skip(n: number) { return this.#sequence.skip(n); } skipLast(n: number) { return this.#sequence.skipLast(n); } skipWhile(condition: AnyPredicate) { return this.#sequence.skipWhile(condition); } take(n: number) { return this.#sequence.take(n); } takeLast(n: number) { return this.#sequence.takeLast(n); } takeWhile(condition: AnyPredicate) { return this.#sequence.takeWhile(condition); } peek(action: Action) { return this.#sequence.peek(action); } forEach(action: Action) { this.#sequence.forEach(action); } zip(sequence: Iterable) { return this.#sequence.zip(sequence); } cartesianProduct(sequence: Iterable) { return this.#sequence.cartesianProduct(sequence); } indexed() { return this.#sequence.indexed(); } reversed() { return this.#sequence.reversed(); } chunked(size: number): Sequence>; chunked(size: number, asArray: true): Sequence; chunked(size: number, transformer: SequencePipeline): Sequence; chunked(size: number, transformerOrAsArray?: any): any { return this.#sequence.chunked(size, transformerOrAsArray); } random(options?: RandomOptions) { return this.#sequence.random(options); } cached() { return this.#sequence.cached(); } awaited(): AsyncSequence> { return this.#sequence.awaited(); } asArray() { return this.#sequence.asArray(); } toArray() { return this.#sequence.toArray(); } toMap(keySelector: Converter): Map; toMap(keySelector: Converter, valueSelector: Converter): Map; toMap(keySelector: any, valueSelector?: any) { return this.#sequence.toMap(keySelector, valueSelector); } toSet() { return this.#sequence.toSet(); } toObject(keySelector: Converter): Record; toObject(keySelector: Converter, valueSelector: Converter): Record; toObject(keySelector: any, valueSelector?: any) { return this.#sequence.toObject(keySelector, valueSelector); } collect(collector: Collector) { return this.#sequence.collect(collector); } } export class GroupedSequenceImpl extends DelegatedSequence implements GroupedSequence { readonly #key: TKey; constructor(key: TKey, grouping: Sequence) { super(grouping); this.#key = key; } public get key() { return this.#key; } override toJSON() { return { key: this.#key, items: this.toArray() }; } } export abstract class BaseOrderedSequence extends BaseSequence implements OrderedSequence { readonly #sequence: Sequence; readonly #sorter: Comparer; readonly #descending: boolean; constructor(sequence: Sequence, sorter: ComparisonOrComparer | undefined, descending: boolean) { super(); this.#sequence = sequence; this.#sorter = sorter ? asComparer(sorter) : defaultComparer; this.#descending = descending; } protected get sequence() { return this.#sequence; } override nonEnumeratedCount() { return this.#sequence.nonEnumeratedCount(); } override maxCount() { return this.#sequence.maxCount(); } get comparer() { return this.#sorter; } get descending() { return this.#descending; } thenSelf(comparer?: ComparisonOrComparer): OrderedSequence { return new ThenOrderSequence(this, false, comparer); } thenBy(selector: Converter, comparer?: ComparisonOrComparer): OrderedSequence { return new ThenOrderBySequence(this, false, selector, comparer); } thenSelfDescending(comparer?: ComparisonOrComparer): OrderedSequence { return new ThenOrderSequence(this, true, comparer); } thenByDescending(selector: Converter, comparer?: ComparisonOrComparer): OrderedSequence { return new ThenOrderBySequence(this, true, selector, comparer); } override *iterator() { const arr = Array.from(this.#sequence); if (this.#sorter) { arr.sort((this.#descending ? this.#sorter.reverse() : this.#sorter).comparison()); } else { arr.sort(); if (this.#descending) { arr.reverse(); } } yield* arr; } } class EmptySequence extends BaseSequence { override nonEnumeratedCount() { return 0; } override *iterator() { } } export const EMPTY = new EmptySequence(); export class RangeSequence extends BaseSequence { readonly #min: number; readonly #max: number; readonly #step: number; constructor(min: number, max: number, step: number) { super(); this.#min = min; this.#max = max; this.#step = step; } get length() { return Math.ceil((this.#max - this.#min) / this.#step); } override nonEnumeratedCount() { return this.length; } override maxCount() { return this.length; } override *iterator() { for (let i = this.#min; i < this.#max; i += this.#step) { yield i; } } } export class BigIntRangeSequence extends BaseSequence { readonly #min: bigint; readonly #max: bigint; readonly #step: bigint; constructor(min: bigint, max: bigint, step: bigint) { super(); this.#min = min; this.#max = max; this.#step = step; } get length() { return Math.ceil(Number((this.#max - this.#min) / this.#step)); } override nonEnumeratedCount() { return this.length; } override maxCount() { return this.length; } override *iterator() { for (let i = this.#min; i < this.#max; i += this.#step) { yield i; } } } export class RepeatSequence extends BaseSequence { readonly #value: T; readonly #count: number; constructor(value: T, count: number) { super(); this.#value = value; this.#count = count; } override nonEnumeratedCount() { return this.#count; } override maxCount() { return this.#count; } override *iterator() { let i = this.#count; while (i-- > 0) { yield this.#value; } } } export class RepeatForeverSequence extends BaseSequence { readonly #value: T; constructor(value: T) { super(); this.#value = value; } override nonEnumeratedCount() { return Infinity; } override maxCount() { return Infinity; } override *iterator() { while (true) { yield this.#value; } } } export class WrappedObject extends BaseSequence { readonly #obj: T; constructor(obj: T) { super(); this.#obj = obj; } override nonEnumeratedCount() { return 1; } override maxCount() { return 1; } override *iterator() { yield this.#obj; } } export class WrappedIterable extends BaseSequence { readonly #iterable: Iterable; constructor(iterable: Iterable) { super(); this.#iterable = iterable; } override iterator() { return this.#iterable[Symbol.iterator](); } } export class WrappedArray extends BaseSequence { readonly #array: ReadonlyArray; constructor(array: ReadonlyArray) { super(); this.#array = array; } get array() { return this.#array; } override nonEnumeratedCount() { return this.#array.length; } override maxCount() { return this.#array.length; } override _countWithoutPredicate() { return this.#array.length; } override contains(obj: T, equater?: EqualityComparisonOrComparer): boolean { if (equater) { const equalityComparer = asEqualityComparer(equater); return this.#array.some(x => equalityComparer.equals(x, obj)); } return this.#array.includes(obj); } override all(predicate: AnyPredicate) { return this.#array.every(predicate); } override any(predicate?: AnyPredicate) { if (predicate) { return this.#array.some(predicate); } return this.#array.length > 0; } override none(predicate?: AnyPredicate) { if (predicate) { return !this.#array.some(predicate); } return this.#array.length === 0; } override toArray() { return this.#array.slice(); } override *iterator() { const length = this.#array.length; for (let i = 0; i < length; i++) { if (i in this.#array) { yield this.#array[i]; } } } } export class WrappedArrayLike extends BaseSequence { readonly #arrayLike: ArrayLike; constructor(arrayLike: ArrayLike) { super(); this.#arrayLike = arrayLike; } get arrayLike() { return this.#arrayLike; } override nonEnumeratedCount() { return this.#arrayLike.length; } override maxCount() { return this.#arrayLike.length; } override toArray() { return Array.from(this.#arrayLike); } override *iterator() { const length = this.#arrayLike.length; for (let i = 0; i < length; i++) { if (i in this.#arrayLike) { yield this.#arrayLike[i]; } } } } export class WrappedSet extends BaseSequence { readonly #set: ReadonlySet; constructor(set: ReadonlySet) { super(); this.#set = set; } override nonEnumeratedCount() { return this.#set.size; } override maxCount() { return this.#set.size; } override contains(obj: T, equater?: EqualityComparisonOrComparer) { if (equater) { return super.contains(obj, equater); } return this.#set.has(obj); } override iterator() { return this.#set.values(); } } export class WrappedMap extends BaseSequence<[K, V]> { readonly #map: ReadonlyMap; constructor(map: ReadonlyMap) { super(); this.#map = map; } override nonEnumeratedCount() { return this.#map.size; } override maxCount() { return this.#map.size; } override contains(obj: [K, V], equater?: EqualityComparisonOrComparer<[K, V]>) { if (equater) { return super.contains(obj, equater); } if (!this.#map.has(obj[0])) { return false; } return this.#map.get(obj[0]) === obj[1]; } override iterator() { return this.#map.entries(); } } export class GeneratorSequence extends BaseSequence { readonly #generator: () => Iterable; constructor(generator: () => Iterable) { super(); this.#generator = generator; } override iterator() { return this.#generator()[Symbol.iterator](); } } export class FunctionSequence extends BaseSequence { readonly #f: () => T; constructor(f: () => T) { super(); this.#f = f; } override nonEnumeratedCount() { return Infinity; } override maxCount() { return Infinity; } override *iterator() { while (true) { yield this.#f(); } } } export class ConcatSequence extends BaseSequence { readonly #sequences: Iterable>; constructor(sequences: Iterable>) { super(); this.#sequences = sequences; } override nonEnumeratedCount() { let n = 0; for (const sequence of this.#sequences) { const m = sequence.nonEnumeratedCount(); if (m < 0) { return super.nonEnumeratedCount(); } n += m; } return n; } override count() { let n = 0; for (const sequence of this.#sequences) { n += sequence.count(); } return n; } override maxCount() { let n = 0; for (const sequence of this.#sequences) { n += sequence.maxCount(); } return n; } override *iterator() { for (const sequence of this.#sequences) { yield* sequence; } } } class DistinctSequence extends BaseSequence { readonly #sequence: Sequence; readonly #equater: EqualityComparisonOrComparer | undefined; constructor(sequence: Sequence, equater?: EqualityComparisonOrComparer) { super(); this.#sequence = sequence; this.#equater = equater; } override maxCount() { return this.#sequence.maxCount(); } override *iterator() { const set = createEqualitySet(this.#equater); for (const obj of this.#sequence) { if (set.add(obj)) { yield obj; } } } } class DistinctBySequence extends BaseSequence { readonly #sequence: Sequence; readonly #converter: Converter; readonly #equater: EqualityComparisonOrComparer | undefined; constructor(sequence: Sequence, converter: Converter, equater?: EqualityComparisonOrComparer) { super(); this.#sequence = sequence; this.#converter = converter; this.#equater = equater; } override maxCount() { return this.#sequence.maxCount(); } override *iterator() { const set = createEqualitySet(this.#equater); for (const obj of this.#sequence) { if (set.add(this.#converter(obj))) { yield obj; } } } } class WhereSequence extends BaseSequence { readonly #sequence: Sequence; readonly #predicate: TypePredicate; constructor(sequence: Sequence, predicate: TypePredicate) { super(); this.#sequence = sequence; this.#predicate = predicate; } override maxCount() { return this.#sequence.maxCount(); } override *iterator() { for (const obj of this.#sequence) { if (this.#predicate(obj)) { yield obj; } } } } class SelectManySequence extends BaseSequence { readonly #sequence: Sequence; readonly #converter: Converter>; constructor(sequence: Sequence, converter: Converter>) { super(); this.#sequence = sequence; this.#converter = converter; } override *iterator() { for (const obj of this.#sequence) { yield* this.#converter(obj); } } } class IndexedSequence extends BaseSequence<[number, T]> { readonly #sequence: Sequence; constructor(sequence: Sequence) { super(); this.#sequence = sequence; } override nonEnumeratedCount() { return this.#sequence.nonEnumeratedCount(); } override maxCount() { return this.#sequence.maxCount(); } override *iterator() { let i = 0; for (const obj of this.#sequence) { yield [i++, obj] as [number, T]; } } } class SelectSequence extends BaseSequence { readonly #sequence: Sequence; readonly #converter: Converter; constructor(sequence: Sequence, converter: Converter) { super(); this.#sequence = sequence; this.#converter = converter; } override nonEnumeratedCount() { return this.#sequence.nonEnumeratedCount(); } override maxCount() { return this.#sequence.maxCount(); } override *iterator() { for (const obj of this.#sequence) { yield this.#converter(obj); } } } class SkipWhileSequence extends BaseSequence { readonly #sequence: Sequence; readonly #predicate: AnyPredicate; constructor(sequence: Sequence, predicate: AnyPredicate) { super(); this.#sequence = sequence; this.#predicate = predicate; } override maxCount() { return this.#sequence.maxCount(); } override *iterator() { const e = Iterator.from(this.#sequence); for (const obj of e) { if (!this.#predicate(obj)) { yield obj; break; } } yield* e; } } class SkipLastSequence extends BaseSequence { readonly #sequence: Sequence; readonly #n: number; constructor(sequence: Sequence, n: number) { super(); this.#sequence = sequence; this.#n = n; } override nonEnumeratedCount() { const n = this.#sequence.nonEnumeratedCount(); return n < 0 ? super.nonEnumeratedCount() : Math.max(0, n - this.#n); } override maxCount() { return Math.max(0, this.#sequence.maxCount() - this.#n); } override *iterator() { const iterator = Iterator.from(this.#sequence); const buffer = new Array(this.#n); // n > 0 let i = 0; do { const next = iterator.next(); if (next.done) { return; } buffer[i++] = next.value; } while (i < this.#n); i = 0; for (const obj of iterator) { yield buffer[i]; buffer[i] = obj; i = (i + 1) % this.#n; } } } class SkipSequence extends BaseSequence { readonly #sequence: Sequence; readonly #n: number; constructor(sequence: Sequence, n: number) { super(); this.#sequence = sequence; this.#n = n; } override nonEnumeratedCount() { const n = this.#sequence.nonEnumeratedCount(); return n < 0 ? super.nonEnumeratedCount() : Math.max(0, n - this.#n); } override maxCount() { return Math.max(0, this.#sequence.maxCount() - this.#n); } override *iterator() { const iterator = Iterator.from(this.#sequence); let i = 0; do { if (iterator.next().done) { return; } i++; } while (i < this.#n); yield* iterator; } } class TakeWhileSequence extends BaseSequence { readonly #sequence: Sequence; readonly #predicate: AnyPredicate; constructor(sequence: Sequence, predicate: AnyPredicate) { super(); this.#sequence = sequence; this.#predicate = predicate; } override maxCount() { return this.#sequence.maxCount(); } override *iterator() { for (const obj of this.#sequence) { if (!this.#predicate(obj)) { return; } yield obj; } } } class TakeLastSequence extends BaseSequence { readonly #sequence: Sequence; readonly #n: number; constructor(sequence: Sequence, n: number) { super(); this.#sequence = sequence; this.#n = n; } override nonEnumeratedCount() { const n = this.#sequence.nonEnumeratedCount(); return n < 0 ? super.nonEnumeratedCount() : Math.min(this.#n, n); } override maxCount() { return Math.min(this.#n, this.#sequence.maxCount()); } override *iterator() { const queue = createQueue(this.#n); for (const obj of this.#sequence) { queue.enqueue(obj); } yield* queue; } } class TakeSequence extends BaseSequence { readonly #sequence: Sequence; readonly #n: number; constructor(sequence: Sequence, n: number) { super(); this.#sequence = sequence; this.#n = n; } override nonEnumeratedCount() { const n = this.#sequence.nonEnumeratedCount(); return n < 0 ? super.nonEnumeratedCount() : Math.min(this.#n, n); } override maxCount() { return Math.min(this.#n, this.#sequence.maxCount()); } override *iterator() { const iterator = this.#sequence.iterator(); let i = this.#n; while (i > 0) { const next = iterator.next(); if (next.done) { return; } yield next.value; i--; } } } class OrderSequence extends BaseOrderedSequence { constructor(sequence: Sequence, descending: boolean, sorter?: ComparisonOrComparer) { super(sequence, sorter, descending); } } class OrderBySequence extends BaseOrderedSequence { constructor(sequence: Sequence, descending: boolean, selector: Converter, sorter?: ComparisonOrComparer) { super(sequence, createComparerUsing(selector, sorter), descending); } } class ThenOrderSequence extends BaseOrderedSequence { constructor(sequence: OrderedSequence, descending: boolean, sorter?: ComparisonOrComparer) { super(sequence, combineComparers([sequence.comparer, sorter]), descending); } } class ThenOrderBySequence extends BaseOrderedSequence { constructor(sequence: OrderedSequence, descending: boolean, selector: Converter, sorter?: ComparisonOrComparer) { super(sequence, combineComparers([sequence.comparer, createComparerUsing(selector, sorter)]), descending); } } class AppendSequence extends BaseSequence { readonly #sequence: Sequence; readonly #obj: T; constructor(sequence: Sequence, obj: T) { super(); this.#sequence = sequence; this.#obj = obj; } override nonEnumeratedCount() { const n = this.#sequence.nonEnumeratedCount(); return n < 0 ? super.nonEnumeratedCount() : n + 1; } override maxCount() { return this.#sequence.maxCount() + 1; } override *iterator() { yield* this.#sequence; yield this.#obj; } } class PrependSequence extends BaseSequence { readonly #sequence: Sequence; readonly #obj: T; constructor(sequence: Sequence, obj: T) { super(); this.#sequence = sequence; this.#obj = obj; } override nonEnumeratedCount() { const n = this.#sequence.nonEnumeratedCount(); return n < 0 ? super.nonEnumeratedCount() : n + 1; } override maxCount() { return this.#sequence.maxCount() + 1; } override *iterator() { yield this.#obj; yield* this.#sequence; } } class PeekSequence extends BaseSequence { readonly #sequence: Sequence; readonly #action: Action; constructor(sequence: Sequence, action: Action) { 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) { this.#action(obj); yield obj; } } } export class ZippedSequence extends BaseSequence<[T, U]> { readonly #first: Sequence; readonly #second: Sequence; constructor(first: Sequence, second: Sequence) { super(); this.#first = first; this.#second = second; } override nonEnumeratedCount() { const first = this.#first.nonEnumeratedCount(); const second = this.#second.nonEnumeratedCount(); return first < 0 || second < 0 ? super.nonEnumeratedCount() : Math.min(first, second); } override maxCount() { return Math.min(this.#first.maxCount(), this.#second.maxCount()); } override *iterator() { const firstIterator = this.#first.iterator(); const secondIterator = this.#second.iterator(); while (true) { const firstNext = firstIterator.next(); const secondNext = secondIterator.next(); if (firstNext.done || secondNext.done) { return; } yield [firstNext.value, secondNext.value] as [T, U]; } } } export class CartesianProductSequence extends BaseSequence<[T, U]> { readonly #first: Sequence; readonly #second: Sequence; constructor(first: Sequence, second: Sequence) { super(); this.#first = first; this.#second = second; } override nonEnumeratedCount() { const n1 = this.#first.nonEnumeratedCount(); if (n1 < 0) { return -1; } const n2 = this.#second.nonEnumeratedCount(); if (n2 < 0) { return -1; } return n1 * n2; } override maxCount() { return this.#first.maxCount() * this.#second.maxCount(); } override *iterator() { for (const firstObj of this.#first) { for (const secondObj of this.#second) { yield [firstObj, secondObj] as [T, U]; } } } } class UnionSequence extends BaseSequence { readonly #first: Sequence; readonly #second: Sequence; readonly #equater: EqualityComparisonOrComparer | undefined; constructor(first: Sequence, second: Sequence, equater?: EqualityComparisonOrComparer) { super(); this.#first = first; this.#second = second; this.#equater = equater; } override maxCount() { return this.#first.maxCount() + this.#second.maxCount(); } *#iterator() { yield* this.#first; yield* this.#second; } override *iterator() { const set = createEqualitySet(this.#equater); for (const obj of this.#iterator()) { if (set.add(obj)) { yield obj; } } } } class UnionBySequence extends BaseSequence { readonly #first: Sequence; readonly #second: Sequence; readonly #selector: Converter; readonly #equater: EqualityComparisonOrComparer | undefined; constructor(first: Sequence, second: Sequence, selector: Converter, equater?: EqualityComparisonOrComparer) { super(); this.#first = first; this.#second = second; this.#selector = selector; this.#equater = equater; } override maxCount() { return this.#first.maxCount() + this.#second.maxCount(); } *#iterator() { yield* this.#first; yield* this.#second; } override *iterator() { const set = createEqualitySet(this.#equater); for (const obj of this.#iterator()) { if (set.add(this.#selector(obj))) { yield obj; } } } } class ExceptSequence extends BaseSequence { readonly #first: Sequence; readonly #second: Sequence; readonly #equater: EqualityComparisonOrComparer | undefined; constructor(first: Sequence, second: Sequence, equater?: EqualityComparisonOrComparer) { super(); this.#first = first; this.#second = second; this.#equater = equater; } override maxCount() { return this.#first.maxCount(); } override *iterator() { const set = createEqualitySet(this.#equater); for (const obj of this.#second) { set.add(obj); } for (const obj of this.#first) { if (set.add(obj)) { yield obj; } } } } class ExceptBySequence extends BaseSequence { readonly #first: Sequence; readonly #second: Sequence; readonly #selector: Converter; readonly #equater: EqualityComparisonOrComparer | undefined; constructor(first: Sequence, second: Sequence, selector: Converter, equater?: EqualityComparisonOrComparer) { super(); this.#first = first; this.#second = second; this.#selector = selector; this.#equater = equater; } override maxCount() { return this.#first.maxCount(); } override *iterator() { const set = createEqualitySet(this.#equater); for (const obj of this.#second) { set.add(this.#selector(obj)); } for (const obj of this.#first) { if (set.add(this.#selector(obj))) { yield obj; } } } } class IntersectSequence extends BaseSequence { readonly #first: Sequence; readonly #second: Sequence; readonly #equater: EqualityComparisonOrComparer | undefined; constructor(first: Sequence, second: Sequence, equater?: EqualityComparisonOrComparer) { super(); this.#first = first; this.#second = second; this.#equater = equater; } override maxCount() { return Math.min(this.#first.maxCount(), this.#second.maxCount()); } override *iterator() { const set = createEqualitySet(this.#equater); set.addAll(this.#second); for (const obj of this.#first) { if (set.remove(obj)) { yield obj; } } } } class IntersectBySequence extends BaseSequence { readonly #first: Sequence; readonly #second: Sequence; readonly #selector: Converter; readonly #equater: EqualityComparisonOrComparer | undefined; constructor(first: Sequence, second: Sequence, selector: Converter, equater?: EqualityComparisonOrComparer) { super(); this.#first = first; this.#second = second; this.#selector = selector; this.#equater = equater; } override maxCount() { return Math.min(this.#first.maxCount(), this.#second.maxCount()); } override *iterator() { const set = createEqualitySet(this.#equater); for (const obj of this.#second) { set.add(this.#selector(obj)); } for (const obj of this.#first) { if (set.remove(this.#selector(obj))) { yield obj; } } } } class ReversedSequence extends BaseSequence { readonly #sequence: Sequence; constructor(sequence: Sequence) { super(); this.#sequence = sequence; } override nonEnumeratedCount() { return this.#sequence.nonEnumeratedCount(); } override maxCount() { return this.#sequence.maxCount(); } override *iterator() { const buffer: T[] = []; for (const obj of this.#sequence) { buffer.push(obj); } while (buffer.length > 0) { yield buffer.pop()!; } } } class GroupBySequence extends BaseSequence> { readonly #sequence: Sequence; readonly #keySelector: Converter; readonly #elementSelector: Converter; readonly #keyEquater: EqualityComparisonOrComparer | undefined; constructor(sequence: Sequence, keySelector: Converter, elementSelector?: Converter, keyEquater?: EqualityComparisonOrComparer) { super(); this.#sequence = sequence; this.#keySelector = keySelector; this.#elementSelector = elementSelector ?? identity as Converter; this.#keyEquater = keyEquater; } override maxCount() { return this.#sequence.maxCount(); } override *iterator() { const groupings = createEqualityMap(this.#keyEquater); for (const obj of this.#sequence) { const key = this.#keySelector(obj); const value = this.#elementSelector(obj); const grouping = groupings.get(key); if (grouping) { grouping.push(value); } else { groupings.set(key, [value]); } } for (const entry of groupings) { yield new GroupedSequenceImpl(entry[0], array(entry[1])); } } } class ChunkedSequence extends BaseSequence> { readonly #sequence: Sequence; readonly #size: number; constructor(sequence: Sequence, size: number) { super(); this.#sequence = sequence; this.#size = size; } override nonEnumeratedCount() { const n = this.#sequence.nonEnumeratedCount(); return n < 0 ? super.nonEnumeratedCount() : Math.ceil(n / this.#size); } override maxCount() { return Math.ceil(this.#sequence.maxCount() / this.#size); } override *iterator() { let chunk: T[] = []; for (const obj of this.#sequence) { chunk.push(obj); if (chunk.length >= this.#size) { yield array(chunk); chunk = []; } } if (chunk.length > 0) { yield array(chunk); } } } class ChunkedArraySequence extends BaseSequence { readonly #sequence: Sequence; readonly #size: number; constructor(sequence: Sequence, size: number) { super(); this.#sequence = sequence; this.#size = size; } override nonEnumeratedCount() { const n = this.#sequence.nonEnumeratedCount(); return n < 0 ? super.nonEnumeratedCount() : Math.ceil(n / this.#size); } override maxCount() { return Math.ceil(this.#sequence.maxCount() / this.#size); } override *iterator() { let chunk: T[] = []; for (const obj of this.#sequence) { chunk.push(obj); if (chunk.length >= this.#size) { yield chunk; chunk = []; } } if (chunk.length > 0) { yield chunk; } } } class JoinSequence extends BaseSequence { readonly #first: Sequence; readonly #second: Sequence; readonly #firstKeySelector: Converter; readonly #secondKeySelector: Converter; readonly #resultSelector: BiConverter; readonly #keyEquater: EqualityComparer; constructor(first: Sequence, second: Sequence, firstKeySelector: Converter, secondKeySelector: Converter, resultSelector?: BiConverter, keyEquater?: EqualityComparisonOrComparer) { super(); this.#first = first; this.#second = second; this.#firstKeySelector = firstKeySelector; this.#secondKeySelector = secondKeySelector; this.#resultSelector = resultSelector ?? JoinSequence.#defaultResultSelector as BiConverter; this.#keyEquater = keyEquater ? asEqualityComparer(keyEquater) : defaultEqualityComparer; } static #defaultResultSelector(first: TOuter, second: TInner): [TOuter, TInner] { return [first, second]; } override maxCount() { return this.#first.maxCount() * this.#second.maxCount(); } override *iterator() { for (const firstObj of this.#first) { const firstKey = this.#firstKeySelector(firstObj); for (const secondObj of this.#second) { const secondKey = this.#secondKeySelector(secondObj); if (this.#keyEquater.equals(firstKey, secondKey)) { yield this.#resultSelector(firstObj, secondObj); } } } } } class GroupJoinSequence extends BaseSequence { readonly #first: Sequence; readonly #second: Sequence; readonly #firstKeySelector: Converter; readonly #secondKeySelector: Converter; readonly #resultSelector: BiConverter, TResult>; readonly #keyEquater: EqualityComparer; constructor(first: Sequence, second: Sequence, firstKeySelector: Converter, secondKeySelector: Converter, resultSelector?: BiConverter, TResult>, keyEquater?: EqualityComparisonOrComparer) { super(); this.#first = first; this.#second = second; this.#firstKeySelector = firstKeySelector; this.#secondKeySelector = secondKeySelector; this.#resultSelector = resultSelector ?? GroupJoinSequence.#defaultResultSelector as BiConverter, TResult>; this.#keyEquater = keyEquater ? asEqualityComparer(keyEquater) : defaultEqualityComparer; } static #defaultResultSelector(first: TOuter, second: Sequence) { return new GroupedSequenceImpl(first, second); } override nonEnumeratedCount() { return this.#first.nonEnumeratedCount(); } override maxCount() { return this.#first.maxCount(); } override *iterator() { for (const firstObj of this.#first) { const firstKey = this.#firstKeySelector(firstObj); const secondObjs: TInner[] = []; for (const secondObj of this.#second) { const secondKey = this.#secondKeySelector(secondObj); if (this.#keyEquater.equals(firstKey, secondKey)) { secondObjs.push(secondObj); } } yield this.#resultSelector(firstObj, array(secondObjs)); } } } class RemoveSequence extends BaseSequence { readonly #sequence: Sequence; readonly #obj: T; readonly #all: boolean; readonly #equater: EqualityComparer; constructor(sequence: Sequence, obj: T, all?: boolean, equater?: EqualityComparisonOrComparer) { super(); this.#sequence = sequence; this.#obj = obj; this.#all = all ?? false; this.#equater = equater ? asEqualityComparer(equater) : defaultEqualityComparer; } override maxCount() { return this.#sequence.maxCount(); } override *iterator() { let gotOne = false; for (const obj of this.#sequence) { if (this.#equater.equals(this.#obj, obj)) { if (this.#all) { continue; } if (!gotOne) { gotOne = true; continue; } } yield obj; } } } class CacheSequence extends BaseSequence { readonly #sequence: Sequence; #cache: T[] | undefined; constructor(sequence: Sequence) { super(); this.#sequence = sequence; } 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; } } } class PartitionSequence extends BaseSequence> { readonly #sequence: Sequence; readonly #equater: EqualityComparisonOrComparer | undefined; constructor(sequence: Sequence, equater: EqualityComparisonOrComparer | undefined) { super(); this.#sequence = sequence; this.#equater = equater; } override *iterator() { const partitions = createEqualityMap(this.#equater); for (const obj of this.#sequence) { const partition = partitions.get(obj); if (partition) { partition.push(obj); } else { partitions.set(obj, [obj]); } } for (const partition of partitions.values()) { yield array(partition); } } } class PartitionBySequence extends BaseSequence> { readonly #sequence: Sequence; readonly #selector: Converter; readonly #equater: EqualityComparisonOrComparer | undefined; constructor(sequence: Sequence, selector: Converter, equater: EqualityComparisonOrComparer | undefined) { super(); this.#sequence = sequence; this.#selector = selector; this.#equater = equater; } override *iterator() { const partitions = createEqualityMap(this.#equater); for (const obj of this.#sequence) { const key = this.#selector(obj); const partition = partitions.get(key); if (partition) { partition.push(obj); } else { partitions.set(key, [obj]); } } for (const partition of partitions.values()) { yield array(partition); } } } class AwaitedSequence extends BaseAsyncSequence> { readonly #sequence: Sequence; constructor(sequence: Sequence) { super(); this.#sequence = sequence; } override async *iterator() { yield* this.#sequence; } }