1
0
Files
sequence-js/src/sync/impl.ts

2407 lines
56 KiB
TypeScript

import { Collector } from "../collector/types.js";
import { createEqualityMap } from "../equality-map.js";
import { createEqualitySet } from "../equality-set.js";
import { createQueue } from "../queue.js";
import { getRandomElement } from "../random/index.js";
import { RandomOptions } from "../random/types.js";
import { Converter, FilterPredicate, Equater, BiConverter, Predicate, Accumulator, Comparer, Action } from "../types.js";
import { strictEquals, identity, operatorCompare, reverseComparer, wrapAsIterable, defaultArrayComparer, combineComparers } from "../utils.js";
import { array, empty, wrap } from "./index.js";
import { Sequence, GroupedSequence, OrderedSequence } from "./types.js";
export class SequenceMarker { }
export abstract class BaseSequence<TElement> extends SequenceMarker implements Sequence<TElement> {
[Symbol.iterator]() {
return this.iterator();
}
abstract iterator(): Iterator<TElement>;
apply<TResult>(pipeline: (sequence: this) => TResult) {
return pipeline(this);
}
select<TResult>(converter: Converter<TElement, TResult>): Sequence<TResult> {
return new SelectSequence<TElement, TResult>(this, converter);
}
selectMany<TResult>(converter: Converter<TElement, Iterable<TResult>>): Sequence<TResult> {
return new SelectManySequence<TElement, TResult>(this, converter);
}
where<TFiltered extends TElement>(predicate: FilterPredicate<TElement, TFiltered>): Sequence<TFiltered> {
return new WhereSequence<TElement, TFiltered>(this, predicate);
}
groupBy<TKey, TResult>(keySelector: Converter<TElement, TKey>, elementSelector?: Converter<TElement, TResult>, keyComparer?: Equater<TKey>): Sequence<GroupedSequence<TKey, TResult>> {
return new GroupBySequence<TElement, TKey, TResult>(this, keySelector, elementSelector, keyComparer);
}
join<TOther, TKey, TResult>(iterable: Iterable<TOther>, firstKeySelector: Converter<TElement, TKey>, secondKeySelector: Converter<TOther, TKey>, resultSelector?: BiConverter<TElement, TOther, TResult>, keyComparer?: Equater<TKey>): Sequence<TResult> {
return new JoinSequence<TElement, TOther, TKey, TResult>(this, wrap(iterable), firstKeySelector, secondKeySelector, resultSelector, keyComparer);
}
groupJoin<TOther, TKey, TResult>(iterable: Iterable<TOther>, firstKeySelector: Converter<TElement, TKey>, secondKeySelector: Converter<TOther, TKey>, resultSelector?: BiConverter<TElement, Sequence<TOther>, TResult>, keyComparer?: Equater<TKey>): Sequence<TResult> {
return new GroupJoinSequence<TElement, TOther, TKey, TResult>(this, wrap(iterable), firstKeySelector, secondKeySelector, resultSelector, keyComparer);
}
contains(obj: TElement, equater?: Equater<TElement>) {
if (!equater) {
equater = strictEquals;
}
for (const element of this) {
if (equater(element, obj)) {
return true;
}
}
return false;
}
sequenceEquals(iterable: Iterable<TElement>, equater?: Equater<TElement>) {
if (this === iterable) {
return true;
}
const that = wrap(iterable);
const thisCount = this.nonEnumeratedCount();
const thatCount = that.nonEnumeratedCount();
if (thisCount >= 0 && thatCount >= 0 && thisCount !== thatCount) {
return false;
}
if (!equater) {
equater = strictEquals;
}
const thisIterator = this.iterator();
const thatIterator = that.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(thisNext.value, thatNext.value)) {
return false;
}
}
}
append(obj: TElement): Sequence<TElement> {
return new AppendSequence<TElement>(this, obj);
}
prepend(obj: TElement): Sequence<TElement> {
return new PrependSequence<TElement>(this, obj);
}
remove(obj: TElement, all?: boolean, equater?: Equater<TElement>): Sequence<TElement> {
return new RemoveSequence<TElement>(this, obj, all, equater);
}
concat(...iterables: Iterable<TElement>[]) {
if (iterables.length === 0) {
return this;
}
const arr: Sequence<TElement>[] = [this];
for (const iterable of iterables) {
arr.push(wrap(iterable));
}
return new ConcatSequence(arr);
}
count(predicate?: Predicate<TElement>) {
let count = 0;
if (predicate) {
for (const element of this) {
if (predicate(element)) {
count++;
}
}
} else {
const iterator = this.iterator();
while (!iterator.next().done) {
count++;
}
}
return count;
}
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?: Predicate<TElement>): { found: boolean, element?: TElement | undefined } {
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?: Predicate<TElement>) {
const result = this.#tryGetFirst(predicate);
if (result.found) {
return result.element!;
}
throw new Error("No element was found.");
}
firstOrDefault(predicate?: Predicate<TElement>, def?: TElement) {
const result = this.#tryGetFirst(predicate);
return result.found ? result.element : def;
}
#tryGetLast(predicate?: Predicate<TElement>): { found: boolean, element?: TElement } {
let found = false;
let result: TElement | undefined = undefined;
if (predicate) {
for (const element of this) {
if (predicate(element)) {
found = true;
result = element;
}
}
} else {
for (const element of this) {
found = true;
result = element;
}
}
return {
found,
element: result
};
}
last(predicate?: Predicate<TElement>) {
const result = this.#tryGetLast(predicate);
if (result.found) {
return result.element!;
}
throw new Error("No element was found.");
}
lastOrDefault(predicate?: Predicate<TElement>, def?: TElement) {
const result = this.#tryGetLast(predicate);
return result.found ? result.element : def;
}
#tryGetSingle(predicate?: Predicate<TElement>): { found: boolean, element?: TElement, reason?: number } {
if (predicate) {
let result: { found: boolean; element: TElement; } | 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 = {
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?: Predicate<TElement>) {
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?: Predicate<TElement>, def?: TElement) {
const result = this.#tryGetSingle(predicate);
return result.found ? result.element : def;
}
#tryElementAt(index: number) {
let i = index;
for (const element of this) {
if (i === 0) {
return {
found: true,
element
} as const;
}
i--;
}
return {
found: false
} as const;
}
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<TAccumulator, TResult>(accumulator: Accumulator<TElement, TAccumulator>, seed?: TAccumulator, resultSelector?: Converter<TAccumulator, TResult>) {
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<TResult>(sorter: Predicate<number>, selector?: Converter<TElement, TResult>, comparer?: Comparer<TResult>) {
const iterator = this.iterator();
let next = iterator.next();
if (next.done) {
throw new Error("Sequence contains no element.")
}
if (!selector) {
selector = identity as Converter<TElement, TResult>;
}
if (!comparer) {
comparer = operatorCompare;
}
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(convertedResult, convertedValue))) {
result = value;
convertedResult = convertedValue;
}
}
return result;
}
min(comparer?: Comparer<TElement>) {
return this.#find(x => x > 0, undefined, comparer);
}
minBy<TBy>(converter: Converter<TElement, TBy>, comparer?: Comparer<TBy>) {
return this.#find(x => x > 0, converter, comparer);
}
max(comparer?: Comparer<TElement>) {
return this.#find(x => x < 0, undefined, comparer);
}
maxBy<TBy>(converter: Converter<TElement, TBy>, comparer?: Comparer<TBy>) {
return this.#find(x => x < 0, converter, comparer);
}
order(comparer?: Comparer<TElement>): OrderedSequence<TElement> {
return new OrderSequence<TElement>(this, false, comparer);
}
orderBy<TBy>(selector: Converter<TElement, TBy>, comparer?: Comparer<TBy>): OrderedSequence<TElement> {
return new OrderBySequence<TElement, TBy>(this, false, selector, comparer);
}
orderDescending(comparer?: Comparer<TElement>): OrderedSequence<TElement> {
return new OrderSequence<TElement>(this, true, comparer);
}
orderByDescending<TBy>(selector: Converter<TElement, TBy>, comparer?: Comparer<TBy>): OrderedSequence<TElement> {
return new OrderBySequence<TElement, TBy>(this, true, selector, comparer);
}
distinct(equater?: Equater<TElement>): Sequence<TElement> {
return new DistinctSequence<TElement>(this, equater);
}
distinctBy<TBy>(selector: Converter<TElement, TBy>, equater?: Equater<TBy>): Sequence<TElement> {
return new DistinctBySequence<TElement, TBy>(this, selector, equater);
}
union(iterable: Iterable<TElement>, equater?: Equater<TElement>): Sequence<TElement> {
return new UnionSequence<TElement>(this, wrap(iterable), equater);
}
unionBy<TBy>(iterable: Iterable<TElement>, selector: Converter<TElement, TBy>, equater?: Equater<TBy>): Sequence<TElement> {
return new UnionBySequence<TElement, TBy>(this, wrap(iterable), selector, equater);
}
except(iterable: Iterable<TElement>): Sequence<TElement> {
return new ExceptSequence<TElement>(this, wrap(iterable));
}
exceptBy<TBy>(iterable: Iterable<TElement>, selector: Converter<TElement, TBy>): Sequence<TElement> {
return new ExceptBySequence<TElement, TBy>(this, wrap(iterable), selector);
}
intersect(iterable: Iterable<TElement>): Sequence<TElement> {
return new IntersectSequence<TElement>(this, wrap(iterable));
}
intersectBy<TBy>(iterable: Iterable<TElement>, selector: Converter<TElement, TBy>): Sequence<TElement> {
return new IntersectBySequence<TElement, TBy>(this, wrap(iterable), selector);
}
all(predicate: Predicate<TElement>) {
const n = this.nonEnumeratedCount();
if (n === 0) {
return false;
}
for (const element of this) {
if (!predicate(element)) {
return false;
}
}
return true;
}
any(predicate?: Predicate<TElement>) {
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?: Predicate<TElement>) {
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<TElement> {
if (n < 0) {
throw new Error("Cannot skip a negative number of elements.");
}
return n === 0 ? this : new SkipSequence<TElement>(this, n);
}
skipLast(n: number): Sequence<TElement> {
if (n < 0) {
throw new Error("Cannot skip a negative number of elements.");
}
return n === 0 ? this : new SkipLastSequence<TElement>(this, n);
}
skipWhile(predicate: Predicate<TElement>): Sequence<TElement> {
return new SkipWhileSequence<TElement>(this, predicate);
}
take(n: number): Sequence<TElement> {
if (n < 0) {
throw new Error("Cannot take a negative number of elements.");
}
return n === 0 ? empty<TElement>() : new TakeSequence<TElement>(this, n);
}
takeLast(n: number): Sequence<TElement> {
if (n < 0) {
throw new Error("Cannot take a negative number of elements.");
}
return n === 0 ? empty<TElement>() : new TakeLastSequence<TElement>(this, n);
}
takeWhile(predicate: Predicate<TElement>): Sequence<TElement> {
return new TakeWhileSequence<TElement>(this, predicate);
}
peek(action: Action<TElement>): Sequence<TElement> {
return new PeekSequence(this, action);
}
forEach(action: Action<TElement>) {
for (const element of this) {
action(element);
}
}
zip<TOther>(iterable: Iterable<TOther>): Sequence<[TElement, TOther]> {
return new ZippedSequence<TElement, TOther>(this, wrap(iterable));
}
indexed(): Sequence<[number, TElement]> {
return new IndexedSequence<TElement>(this);
}
reversed(): Sequence<TElement> {
return new ReversedSequence<TElement>(this);
}
chunked(size: number): Sequence<TElement[]> {
if (size <= 0) {
throw new Error("Chunk size must be positive.");
}
return new ChunkedSequence<TElement>(this, size);
}
random(options?: RandomOptions<TElement>) {
return getRandomElement(this, options).element;
}
cached(): Sequence<TElement> {
return new CacheSequence<TElement>(this);
}
asArray() {
return this.toArray();
}
toArray() {
return Array.from(this);
}
toMap<TKey, TValue>(keySelector: Converter<TElement, TKey>, valueSelector: Converter<TElement, TValue>) {
const map = new Map<TKey, TValue>();
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<TKey extends PropertyKey, TValue>(keySelector: Converter<TElement, TKey>, valueSelector: Converter<TElement, TValue>) {
const obj: Record<PropertyKey, TValue> = {};
for (const element of this) {
const key = keySelector(element);
const value = valueSelector(element);
obj[key] = value;
}
return obj;
}
collect<TResult>(collector: Collector<TElement, any, TResult>) {
const acc = collector.initialize();
for (const e of this) {
collector.accumulate(acc, e);
}
return collector.finalize(acc);
}
}
export class DelegatedSequence<TElement> extends SequenceMarker implements Sequence<TElement> {
#sequence: Sequence<TElement>;
constructor(sequence: Sequence<TElement>) {
super();
this.#sequence = sequence;
}
get sequence() {
return this.#sequence;
}
protected set sequence(value: Sequence<TElement>) {
this.#sequence = value;
}
[Symbol.iterator]() {
return this.iterator();
}
iterator() {
return this.#sequence.iterator();
}
apply<TResult>(pipeline: (sequence: Sequence<TElement>) => TResult) {
return this.#sequence.apply(pipeline);
}
count(predicate?: Predicate<TElement>) {
return this.#sequence.count(predicate);
}
nonEnumeratedCount() {
return this.#sequence.nonEnumeratedCount();
}
fastCount() {
return this.#sequence.fastCount();
}
maxCount() {
return this.#sequence.maxCount();
}
select<TResult>(selector: Converter<TElement, TResult>) {
return this.#sequence.select(selector);
}
selectMany<TResult>(selector: Converter<TElement, Iterable<TResult>>) {
return this.#sequence.selectMany(selector);
}
where<TFiltered extends TElement>(predicate: FilterPredicate<TElement, TFiltered>) {
return this.#sequence.where(predicate);
}
groupBy<TKey, TResult>(keySelector: Converter<TElement, TKey>, elementSelector?: Converter<TElement, TResult>, keyComparer?: Equater<TKey>) {
//@ts-ignore
return this.#sequence.groupBy(keySelector, elementSelector, keyComparer);
}
join<TOther, TKey, TResult>(iterable: Iterable<TOther>, firstKeySelector: Converter<TElement, TKey>, secondKeySelector: Converter<TOther, TKey>, resultSelector?: BiConverter<TElement, TOther, TResult>, keyComparer?: Equater<TKey>) {
//@ts-ignore
return this.#sequence.join(iterable, firstKeySelector, secondKeySelector, resultSelector, keyComparer);
}
groupJoin<TOther, TKey, TResult>(iterable: Iterable<TOther>, firstKeySelector: Converter<TElement, TKey>, secondKeySelector: Converter<TOther, TKey>, resultSelector?: BiConverter<TElement, Sequence<TOther>, TResult>, keyComparer?: Equater<TKey>) {
//@ts-ignore
return this.#sequence.groupJoin(iterable, firstKeySelector, secondKeySelector, resultSelector, keyComparer);
}
contains(obj: TElement, equater?: Equater<TElement>) {
return this.#sequence.contains(obj, equater);
}
sequenceEquals(iterable: Iterable<TElement>, equater?: Equater<TElement>) {
return this.#sequence.sequenceEquals(iterable, equater);
}
append(obj: TElement) {
return this.#sequence.append(obj);
}
prepend(obj: TElement) {
return this.#sequence.prepend(obj);
}
remove(obj: TElement, all?: boolean, equater?: Equater<TElement>) {
return this.#sequence.remove(obj, all, equater);
}
concat(...iterables: Iterable<TElement>[]) {
return this.#sequence.concat(...iterables);
}
first(predicate?: Predicate<TElement>) {
return this.#sequence.first(predicate);
}
firstOrDefault(predicate?: Predicate<TElement>, def?: TElement) {
return this.#sequence.firstOrDefault(predicate, def);
}
last(predicate?: Predicate<TElement>) {
return this.#sequence.last(predicate);
}
lastOrDefault(predicate?: Predicate<TElement>, def?: TElement) {
return this.#sequence.lastOrDefault(predicate, def);
}
single(predicate?: Predicate<TElement>) {
return this.#sequence.single(predicate);
}
singleOrDefault(predicate?: Predicate<TElement>, 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<TAccumulator, TResult>(accumulator: Accumulator<TElement, TAccumulator>, seed?: TAccumulator, resultSelector?: Converter<TAccumulator, TResult>) {
return this.#sequence.aggregate(accumulator, seed, resultSelector);
}
min(comparer?: Comparer<TElement>) {
return this.#sequence.min(comparer);
}
minBy<TBy>(selector: Converter<TElement, TBy>, comparer?: Comparer<TBy>) {
return this.#sequence.minBy(selector, comparer);
}
max(comparer?: Comparer<TElement>) {
return this.#sequence.max(comparer);
}
maxBy<TBy>(selector: Converter<TElement, TBy>, comparer?: Comparer<TBy>) {
return this.#sequence.maxBy(selector, comparer);
}
order(comparer?: Comparer<TElement>) {
return this.#sequence.order(comparer);
}
orderBy<TBy>(selector: Converter<TElement, TBy>, comparer?: Comparer<TBy>) {
return this.#sequence.orderBy(selector, comparer);
}
orderDescending(comparer?: Comparer<TElement>) {
return this.#sequence.orderDescending(comparer);
}
orderByDescending<TBy>(selector: Converter<TElement, TBy>, comparer?: Comparer<TBy>) {
return this.#sequence.orderByDescending(selector, comparer);
}
distinct(equater?: Equater<TElement>) {
return this.#sequence.distinct(equater);
}
distinctBy<TBy>(selector: Converter<TElement, TBy>, equater?: Equater<TBy>) {
return this.#sequence.distinctBy(selector, equater);
}
union(iterable: Iterable<TElement>, equater?: Equater<TElement>) {
return this.#sequence.union(iterable, equater);
}
unionBy<TBy>(iterable: Iterable<TElement>, selector: Converter<TElement, TBy>, equater?: Equater<TBy>) {
return this.#sequence.unionBy(iterable, selector, equater);
}
except(iterable: Iterable<TElement>, equater?: Equater<TElement>) {
return this.#sequence.except(iterable, equater);
}
exceptBy<TBy>(iterable: Iterable<TElement>, selector: Converter<TElement, TBy>, equater?: Equater<TBy>) {
return this.#sequence.exceptBy(iterable, selector, equater);
}
intersect(iterable: Iterable<TElement>, equater?: Equater<TElement>) {
return this.#sequence.intersect(iterable, equater);
}
intersectBy<TBy>(iterable: Iterable<TElement>, selector: Converter<TElement, TBy>, equater?: Equater<TBy>) {
return this.#sequence.intersectBy(iterable, selector, equater);
}
all(predicate: Predicate<TElement>) {
return this.#sequence.all(predicate);
}
any(predicate?: Predicate<TElement>) {
//@ts-ignore
return this.#sequence.any(predicate);
}
none(predicate?: Predicate<TElement>) {
//@ts-ignore
return this.#sequence.none(predicate);
}
skip(n: number) {
return this.#sequence.skip(n);
}
skipLast(n: number) {
return this.#sequence.skipLast(n);
}
skipWhile(condition: Predicate<TElement>) {
return this.#sequence.skipWhile(condition);
}
take(n: number) {
return this.#sequence.take(n);
}
takeLast(n: number) {
return this.#sequence.takeLast(n);
}
takeWhile(condition: Predicate<TElement>) {
return this.#sequence.takeWhile(condition);
}
peek(action: Action<TElement>) {
return this.#sequence.peek(action);
}
forEach(action: Action<TElement>) {
this.#sequence.forEach(action);
}
zip<TOther>(iterable: Iterable<TOther>) {
return this.#sequence.zip(iterable);
}
indexed() {
return this.#sequence.indexed();
}
reversed() {
return this.#sequence.reversed();
}
chunked(size: number) {
return this.#sequence.chunked(size);
}
random(options?: RandomOptions<TElement>) {
return this.#sequence.random(options);
}
cached() {
return this.#sequence.cached();
}
asArray() {
return this.#sequence.asArray();
}
toArray() {
return this.#sequence.toArray();
}
toMap<TKey, TValue>(keySelector: Converter<TElement, TKey>, valueSelector: Converter<TElement, TValue>) {
return this.#sequence.toMap(keySelector, valueSelector);
}
toSet() {
return this.#sequence.toSet();
}
toObject<TKey extends PropertyKey, TValue>(keySelector: Converter<TElement, TKey>, valueSelector: Converter<TElement, TValue>) {
return this.#sequence.toObject(keySelector, valueSelector);
}
collect<TResult>(collector: Collector<TElement, any, TResult>) {
return this.#sequence.collect(collector);
}
}
export class GroupedSequenceImpl<TKey, TElement> extends DelegatedSequence<TElement> implements GroupedSequence<TKey, TElement> {
readonly #key: TKey;
constructor(key: TKey, grouping: Sequence<TElement>) {
super(grouping);
this.#key = key;
}
public get key() {
return this.#key;
}
}
export abstract class BaseOrderedSequence<TElement> extends BaseSequence<TElement> implements OrderedSequence<TElement> {
readonly #sequence: Sequence<TElement>;
readonly #sorter: Comparer<TElement> | undefined;
readonly #descending: boolean;
constructor(sequence: Sequence<TElement>, sorter: Comparer<TElement> | undefined, descending: boolean) {
super();
this.#sequence = sequence;
this.#sorter = sorter;
this.#descending = descending;
}
override nonEnumeratedCount() {
return this.#sequence.nonEnumeratedCount();
}
override maxCount() {
return this.#sequence.maxCount();
}
get comparer() {
return this.#sorter;
}
thenSelf(comparer?: Comparer<TElement>): OrderedSequence<TElement> {
return new ThenOrderSequence(this, false, comparer);
}
thenBy<TBy>(selector: Converter<TElement, TBy>, comparer?: Comparer<TBy>): OrderedSequence<TElement> {
return new ThenOrderBySequence<TElement, TBy>(this, false, selector, comparer);
}
thenSelfDescending(comparer?: Comparer<TElement>): OrderedSequence<TElement> {
return new ThenOrderSequence(this, true, comparer);
}
thenByDescending<TBy>(selector: Converter<TElement, TBy>, comparer?: Comparer<TBy>): OrderedSequence<TElement> {
return new ThenOrderBySequence<TElement, TBy>(this, true, selector, comparer);
}
override *iterator() {
const arr: TElement[] = [];
for (const obj of this.#sequence) {
arr.push(obj);
}
if (this.#sorter) {
arr.sort(this.#descending ? reverseComparer(this.#sorter) : this.#sorter);
} else {
arr.sort();
if (this.#descending) {
arr.reverse();
}
}
yield* arr;
}
}
export class EmptySequence<T> extends BaseSequence<T> {
static readonly INSTANCE = new EmptySequence<any>();
override nonEnumeratedCount() {
return 0;
}
override maxCount() {
return 0;
}
override *iterator() { }
}
export class RangeSequence extends BaseSequence<number> {
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<bigint> {
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<T> extends BaseSequence<T> {
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<T> extends BaseSequence<T> {
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<T> extends BaseSequence<T> {
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<T> extends BaseSequence<T> {
readonly #iterable: Iterable<T>;
constructor(iterable: Iterable<T>) {
super();
this.#iterable = iterable;
}
override iterator() {
return this.#iterable[Symbol.iterator]();
}
}
export class WrappedArray<T> extends BaseSequence<T> {
readonly #array: T[];
constructor(array: T[]) {
super();
this.#array = array;
}
override nonEnumeratedCount() {
return this.#array.length;
}
override maxCount() {
return this.#array.length;
}
override contains(obj: T, equater?: Equater<T>): boolean {
if (equater) {
return this.#array.some(x => equater(x, obj));
}
return this.#array.includes(obj);
}
override all(predicate: Predicate<T>) {
return this.#array.every(predicate);
}
override any(predicate?: Predicate<T>) {
if (predicate) {
return this.#array.some(predicate);
}
return this.#array.length > 0;
}
override none(predicate?: Predicate<T>) {
if (predicate) {
return !this.#array.some(predicate);
}
return this.#array.length === 0;
}
override asArray() {
return this.#array;
}
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<T> extends BaseSequence<T> {
readonly #arrayLike: ArrayLike<T>;
constructor(arrayLike: ArrayLike<T>) {
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<T> extends BaseSequence<T> {
readonly #set: Set<T>;
constructor(set: Set<T>) {
super();
this.#set = set;
}
override nonEnumeratedCount() {
return this.#set.size;
}
override maxCount() {
return this.#set.size;
}
override contains(obj: T, equater?: Equater<T>) {
if (equater) {
return super.contains(obj, equater);
}
return this.#set.has(obj);
}
override iterator() {
return this.#set.values();
}
}
export class WrappedMap<K, V> extends BaseSequence<[K, V]> {
readonly #map: Map<K, V>;
constructor(map: Map<K, V>) {
super();
this.#map = map;
}
override nonEnumeratedCount() {
return this.#map.size;
}
override maxCount() {
return this.#map.size;
}
override contains(obj: [K, V], equater?: Equater<[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<T> extends BaseSequence<T> {
readonly #generator: () => Iterable<T>;
constructor(generator: () => Iterable<T>) {
super();
this.#generator = generator;
}
override iterator() {
return this.#generator()[Symbol.iterator]();
}
}
export class FunctionSequence<T> extends BaseSequence<T> {
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<T> extends BaseSequence<T> {
readonly #sequences: Iterable<Sequence<T>>;
constructor(sequences: Iterable<Sequence<T>>) {
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;
}
}
}
export class DistinctSequence<T> extends BaseSequence<T> {
readonly #sequence: Sequence<T>;
readonly #equater: Equater<T> | undefined;
constructor(sequence: Sequence<T>, equater?: Equater<T>) {
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;
}
}
}
}
export class DistinctBySequence<T, U> extends BaseSequence<T> {
readonly #sequence: Sequence<T>;
readonly #selector: Converter<T, U>;
readonly #equater: Equater<U> | undefined;
constructor(sequence: Sequence<T>, selector: Converter<T, U>, equater?: Equater<U>) {
super();
this.#sequence = sequence;
this.#selector = selector;
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.#selector(obj))) {
yield obj;
}
}
}
}
export class WhereSequence<TElement, TFiltered extends TElement> extends BaseSequence<TFiltered> {
readonly #sequence: Sequence<TElement>;
readonly #predicate: FilterPredicate<TElement, TFiltered>;
constructor(sequence: Sequence<TElement>, predicate: FilterPredicate<TElement, TFiltered>) {
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;
}
}
}
}
export class SelectManySequence<T, U> extends BaseSequence<U> {
readonly #sequence: Sequence<T>;
readonly #converter: Converter<T, Iterable<U>>;
constructor(sequence: Sequence<T>, converter: Converter<T, Iterable<U>>) {
super();
this.#sequence = sequence;
this.#converter = converter;
}
override *iterator() {
for (const obj of this.#sequence) {
yield* this.#converter(obj);
}
}
}
export class IndexedSequence<T> extends BaseSequence<[number, T]> {
readonly #sequence: Sequence<T>;
constructor(sequence: Sequence<T>) {
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];
}
}
}
export class SelectSequence<T, U> extends BaseSequence<U> {
readonly #sequence: Sequence<T>;
readonly #converter: Converter<T, U>;
constructor(sequence: Sequence<T>, converter: Converter<T, U>) {
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);
}
}
}
export class SkipWhileSequence<T> extends BaseSequence<T> {
readonly #sequence: Sequence<T>;
readonly #predicate: Predicate<T>;
constructor(sequence: Sequence<T>, predicate: Predicate<T>) {
super();
this.#sequence = sequence;
this.#predicate = predicate;
}
override maxCount() {
return this.#sequence.maxCount();
}
override *iterator() {
const e = wrapAsIterable(this.#sequence.iterator());
for (const obj of e) {
if (!this.#predicate(obj)) {
yield obj;
break;
}
}
yield* e;
}
}
export class SkipLastSequence<T> extends BaseSequence<T> {
readonly #sequence: Sequence<T>;
readonly #n: number;
constructor(sequence: Sequence<T>, 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 = this.#sequence.iterator();
const buffer = new Array<T>(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 wrapAsIterable(iterator)) {
yield buffer[i];
buffer[i] = obj;
i = (i + 1) % this.#n;
}
}
}
export class SkipSequence<T> extends BaseSequence<T> {
readonly #sequence: Sequence<T>;
readonly #n: number;
constructor(sequence: Sequence<T>, 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 = this.#sequence.iterator();
let i = 0;
do {
if (iterator.next().done) {
return;
}
i++;
} while (i < this.#n);
yield* wrapAsIterable(iterator);
}
}
export class TakeWhileSequence<T> extends BaseSequence<T> {
readonly #sequence: Sequence<T>;
readonly #predicate: Predicate<T>;
constructor(sequence: Sequence<T>, predicate: Predicate<T>) {
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;
}
}
}
export class TakeLastSequence<T> extends BaseSequence<T> {
readonly #sequence: Sequence<T>;
readonly #n: number;
constructor(sequence: Sequence<T>, 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<T>(this.#n);
for (const obj of this.#sequence) {
queue.enqueue(obj);
}
yield* queue;
}
}
export class TakeSequence<T> extends BaseSequence<T> {
readonly #sequence: Sequence<T>;
readonly #n: number;
constructor(sequence: Sequence<T>, 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--;
}
}
}
export class OrderSequence<T> extends BaseOrderedSequence<T> {
constructor(sequence: Sequence<T>, descending: boolean, sorter?: Comparer<T>) {
super(sequence, sorter, descending);
}
}
export class OrderBySequence<T, U> extends BaseOrderedSequence<T> {
constructor(sequence: Sequence<T>, descending: boolean, selector: Converter<T, U>, sorter?: Comparer<U>) {
super(sequence, OrderBySequence.#createSorter(selector, sorter), descending);
}
static #createSorter<T, U>(selector: Converter<T, U>, sorter?: Comparer<U>) {
const _sorter = sorter ?? defaultArrayComparer;
return (a: T, b: T) => _sorter(selector(a), selector(b));
}
}
export class ThenOrderSequence<T> extends BaseOrderedSequence<T> {
constructor(sequence: OrderedSequence<T>, descending: boolean, sorter?: Comparer<T>) {
super(sequence, combineComparers(sequence.comparer ?? defaultArrayComparer, sorter ?? defaultArrayComparer), descending);
}
}
export class ThenOrderBySequence<T, U> extends BaseOrderedSequence<T> {
constructor(sequence: OrderedSequence<T>, descending: boolean, selector: Converter<T, U>, sorter?: Comparer<U>) {
super(sequence, ThenOrderBySequence.#createCombinedSorter(sequence.comparer, selector, sorter), descending);
}
static #createCombinedSorter<T, U>(baseSorter: Comparer<T> | undefined, selector: Converter<T, U>, sorter?: Comparer<U>) {
const _baseSorter = baseSorter ?? defaultArrayComparer;
const _sorter = sorter ?? defaultArrayComparer;
return combineComparers(_baseSorter, (a: T, b: T) => _sorter(selector(a), selector(b)));
}
}
export class AppendSequence<T> extends BaseSequence<T> {
readonly #sequence: Sequence<T>;
readonly #obj: T;
constructor(sequence: Sequence<T>, 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;
}
}
export class PrependSequence<T> extends BaseSequence<T> {
readonly #sequence: Sequence<T>;
readonly #obj: T;
constructor(sequence: Sequence<T>, 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;
}
}
export class PeekSequence<T> extends DelegatedSequence<T> {
readonly #action: Action<T>;
constructor(sequence: Sequence<T>, action: Action<T>) {
super(sequence);
this.#action = action;
}
override *iterator() {
for (const obj of wrapAsIterable(super.iterator())) {
this.#action(obj);
yield obj;
}
}
}
export class ZippedSequence<T, U> extends BaseSequence<[T, U]> {
readonly #first: Sequence<T>;
readonly #second: Sequence<U>;
constructor(first: Sequence<T>, second: Sequence<U>) {
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 UnionSequence<T> extends BaseSequence<T> {
readonly #first: Sequence<T>;
readonly #second: Sequence<T>;
readonly #equater: Equater<T> | undefined;
constructor(first: Sequence<T>, second: Sequence<T>, equater?: Equater<T>) {
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;
}
}
}
}
export class UnionBySequence<T, U> extends BaseSequence<T> {
readonly #first: Sequence<T>;
readonly #second: Sequence<T>;
readonly #selector: Converter<T, U>;
readonly #equater: Equater<U> | undefined;
constructor(first: Sequence<T>, second: Sequence<T>, selector: Converter<T, U>, equater?: Equater<U>) {
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;
}
}
}
}
export class ExceptSequence<T> extends BaseSequence<T> {
readonly #first: Sequence<T>;
readonly #second: Sequence<T>;
readonly #equater: Equater<T> | undefined;
constructor(first: Sequence<T>, second: Sequence<T>, equater?: Equater<T>) {
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;
}
}
}
}
export class ExceptBySequence<T, U> extends BaseSequence<T> {
readonly #first: Sequence<T>;
readonly #second: Sequence<T>;
readonly #selector: Converter<T, U>;
readonly #equater: Equater<U> | undefined;
constructor(first: Sequence<T>, second: Sequence<T>, selector: Converter<T, U>, equater?: Equater<U>) {
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;
}
}
}
}
export class IntersectSequence<T> extends BaseSequence<T> {
readonly #first: Sequence<T>;
readonly #second: Sequence<T>;
readonly #equater: Equater<T> | undefined;
constructor(first: Sequence<T>, second: Sequence<T>, equater?: Equater<T>) {
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);
for (const obj of this.#second) {
set.add(obj);
}
for (const obj of this.#first) {
if (set.remove(obj)) {
yield obj;
}
}
}
}
export class IntersectBySequence<T, U> extends BaseSequence<T> {
readonly #first: Sequence<T>;
readonly #second: Sequence<T>;
readonly #selector: Converter<T, U>;
readonly #equater: Equater<U> | undefined;
constructor(first: Sequence<T>, second: Sequence<T>, selector: Converter<T, U>, equater?: Equater<U>) {
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;
}
}
}
}
export class ReversedSequence<T> extends BaseSequence<T> {
readonly #sequence: Sequence<T>;
constructor(sequence: Sequence<T>) {
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()!;
}
}
}
export class GroupBySequence<TElement, TKey, TResult> extends BaseSequence<GroupedSequence<TKey, TResult>> {
readonly #sequence: Sequence<TElement>;
readonly #keySelector: Converter<TElement, TKey>;
readonly #elementSelector: Converter<TElement, TResult>;
readonly #keyComparer: Equater<TKey> | undefined;
constructor(sequence: Sequence<TElement>, keySelector: Converter<TElement, TKey>, elementSelector?: Converter<TElement, TResult>, keyComparer?: Equater<TKey>) {
super();
this.#sequence = sequence;
this.#keySelector = keySelector;
this.#elementSelector = elementSelector ?? identity as Converter<TElement, TResult>;
this.#keyComparer = keyComparer;
}
override maxCount() {
return this.#sequence.maxCount();
}
override *iterator() {
const groupings = createEqualityMap<TKey, TResult[]>(this.#keyComparer);
for (const obj of this.#sequence) {
const key = this.#keySelector(obj);
let grouping = groupings.get(key);
if (!grouping) {
groupings.set(key, grouping = []);
}
grouping.push(this.#elementSelector(obj));
}
for (const entry of groupings) {
yield new GroupedSequenceImpl(entry[0], array(entry[1]));
}
}
}
export class ChunkedSequence<T> extends BaseSequence<T[]> {
readonly #sequence: Sequence<T>;
readonly #size: number;
constructor(sequence: Sequence<T>, 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;
}
}
}
export class JoinSequence<TOuter, TInner, TKey, TResult> extends BaseSequence<TResult> {
readonly #first: Sequence<TOuter>;
readonly #second: Sequence<TInner>;
readonly #firstKeySelector: Converter<TOuter, TKey>;
readonly #secondKeySelector: Converter<TInner, TKey>;
readonly #resultSelector: BiConverter<TOuter, TInner, TResult>;
readonly #keyComparer: Equater<TKey>;
constructor(first: Sequence<TOuter>, second: Sequence<TInner>, firstKeySelector: Converter<TOuter, TKey>, secondKeySelector: Converter<TInner, TKey>, resultSelector?: BiConverter<TOuter, TInner, TResult>, keyComparer?: Equater<TKey>) {
super();
this.#first = first;
this.#second = second;
this.#firstKeySelector = firstKeySelector;
this.#secondKeySelector = secondKeySelector;
this.#resultSelector = resultSelector ?? JoinSequence.#defaultResultSelector as BiConverter<TOuter, TInner, TResult>;
this.#keyComparer = keyComparer ?? strictEquals;
}
static #defaultResultSelector<TOuter, TInner>(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.#keyComparer(firstKey, secondKey)) {
yield this.#resultSelector(firstObj, secondObj);
}
}
}
}
}
export class GroupJoinSequence<TOuter, TInner, TKey, TResult> extends BaseSequence<TResult> {
readonly #first: Sequence<TOuter>;
readonly #second: Sequence<TInner>;
readonly #firstKeySelector: Converter<TOuter, TKey>;
readonly #secondKeySelector: Converter<TInner, TKey>;
readonly #resultSelector: BiConverter<TOuter, Sequence<TInner>, TResult>;
readonly #keyComparer: Equater<TKey>;
constructor(first: Sequence<TOuter>, second: Sequence<TInner>, firstKeySelector: Converter<TOuter, TKey>, secondKeySelector: Converter<TInner, TKey>, resultSelector?: BiConverter<TOuter, Sequence<TInner>, TResult>, keyComparer?: Equater<TKey>) {
super();
this.#first = first;
this.#second = second;
this.#firstKeySelector = firstKeySelector;
this.#secondKeySelector = secondKeySelector;
this.#resultSelector = resultSelector ?? GroupJoinSequence.#defaultResultSelector as BiConverter<TOuter, Sequence<TInner>, TResult>;
this.#keyComparer = keyComparer ?? strictEquals;
}
static #defaultResultSelector<TOuter, TInner>(first: TOuter, second: Sequence<TInner>) {
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.#keyComparer(firstKey, secondKey)) {
secondObjs.push(secondObj);
}
}
yield this.#resultSelector(firstObj, array(secondObjs));
}
}
}
export class RemoveSequence<T> extends BaseSequence<T> {
readonly #sequence: Sequence<T>;
readonly #obj: T;
readonly #all: boolean;
readonly #equater: Equater<T>;
constructor(sequence: Sequence<T>, obj: T, all?: boolean, equater?: Equater<T>) {
super();
this.#sequence = sequence;
this.#obj = obj;
this.#all = all ?? false;
this.#equater = equater ?? strictEquals;
}
override maxCount() {
return this.#sequence.maxCount();
}
override *iterator() {
let gotOne = false;
for (const obj of this.#sequence) {
if (this.#equater(this.#obj, obj)) {
if (this.#all) {
continue;
}
if (!gotOne) {
gotOne = true;
continue;
}
}
yield obj;
}
}
}
export class CacheSequence<T> extends DelegatedSequence<T> {
#cached = false;
constructor(sequence: Sequence<T>) {
super(sequence);
}
override iterator() {
if (!this.#cached) {
this.sequence = array(this.sequence.toArray());
this.#cached = true;
}
return super.iterator();
}
}