2722 lines
67 KiB
TypeScript
2722 lines
67 KiB
TypeScript
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<TElement> extends SequenceMarker implements Sequence<TElement> {
|
|
[Symbol.iterator]() {
|
|
return this.iterator();
|
|
}
|
|
|
|
override valueOf() {
|
|
return this.toJSON();
|
|
}
|
|
|
|
toJSON() {
|
|
return this.asArray();
|
|
}
|
|
|
|
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: TypePredicate<TElement, TFiltered>): Sequence<TFiltered>;
|
|
where(predicate: AnyPredicate<TElement>): Sequence<TElement>;
|
|
where(predicate: any) {
|
|
return new WhereSequence<TElement, any>(this, predicate);
|
|
}
|
|
|
|
groupBy<TKey, TResult>(keySelector: Converter<TElement, TKey>, elementSelector?: Converter<TElement, TResult>, keyComparer?: EqualityComparisonOrComparer<TKey>): Sequence<GroupedSequence<TKey, TResult>> {
|
|
return new GroupBySequence<TElement, TKey, TResult>(this, keySelector, elementSelector, keyComparer);
|
|
}
|
|
|
|
join<TOther, TKey, TResult>(sequence: Iterable<TOther>, firstKeySelector: Converter<TElement, TKey>, secondKeySelector: Converter<TOther, TKey>, resultSelector?: BiConverter<TElement, TOther, TResult>, keyComparer?: EqualityComparisonOrComparer<TKey>): Sequence<TResult> {
|
|
return new JoinSequence<TElement, TOther, TKey, TResult>(this, wrap(sequence), firstKeySelector, secondKeySelector, resultSelector, keyComparer);
|
|
}
|
|
|
|
groupJoin<TOther, TKey, TResult>(sequence: Iterable<TOther>, firstKeySelector: Converter<TElement, TKey>, secondKeySelector: Converter<TOther, TKey>, resultSelector?: BiConverter<TElement, Iterable<TOther>, TResult>, keyComparer?: EqualityComparisonOrComparer<TKey>): Sequence<TResult> {
|
|
return new GroupJoinSequence<TElement, TOther, TKey, TResult>(this, wrap(sequence), firstKeySelector, secondKeySelector, resultSelector, keyComparer);
|
|
}
|
|
|
|
contains(obj: TElement, equater?: EqualityComparisonOrComparer<TElement>) {
|
|
equater = equater ? asEqualityComparer(equater) : defaultEqualityComparer;
|
|
|
|
for (const element of this) {
|
|
if (equater.equals(element, obj)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
sequenceEquals(sequence: Iterable<TElement>, equater?: EqualityComparisonOrComparer<TElement>) {
|
|
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<TElement> {
|
|
return new AppendSequence<TElement>(this, obj);
|
|
}
|
|
|
|
prepend(obj: TElement): Sequence<TElement> {
|
|
return new PrependSequence<TElement>(this, obj);
|
|
}
|
|
|
|
remove(obj: TElement, all?: boolean, equater?: EqualityComparisonOrComparer<TElement>): Sequence<TElement> {
|
|
return new RemoveSequence<TElement>(this, obj, all, equater);
|
|
}
|
|
|
|
concat(...sequences: Iterable<TElement>[]) {
|
|
if (sequences.length === 0) {
|
|
return this;
|
|
}
|
|
|
|
const arr: Sequence<TElement>[] = [this];
|
|
|
|
for (const sequence of sequences) {
|
|
arr.push(wrap(sequence));
|
|
}
|
|
|
|
return new ConcatSequence(arr);
|
|
}
|
|
|
|
_countWithPredicate(predicate: AnyPredicate<TElement>) {
|
|
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<TElement>) {
|
|
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<TElement>): FindElementResult<TElement> {
|
|
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<TElement>) {
|
|
const result = this.#tryGetFirst(predicate);
|
|
|
|
if (result.found) {
|
|
return result.element;
|
|
}
|
|
|
|
throw new Error("No element was found.");
|
|
}
|
|
|
|
firstOrDefault(predicate?: AnyPredicate<TElement>, def?: TElement) {
|
|
const result = this.#tryGetFirst(predicate);
|
|
|
|
return result.found ? result.element : def;
|
|
}
|
|
|
|
#tryGetLast(predicate?: AnyPredicate<TElement>): FindElementResult<TElement> {
|
|
let result: FindElementResult<TElement> = {
|
|
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<TElement>) {
|
|
const result = this.#tryGetLast(predicate);
|
|
|
|
if (result.found) {
|
|
return result.element;
|
|
}
|
|
|
|
throw new Error("No element was found.");
|
|
}
|
|
|
|
lastOrDefault(predicate?: AnyPredicate<TElement>, def?: TElement) {
|
|
const result = this.#tryGetLast(predicate);
|
|
|
|
return result.found ? result.element : def;
|
|
}
|
|
|
|
#tryGetSingle(predicate?: AnyPredicate<TElement>): FindElementResult<TElement> {
|
|
if (predicate) {
|
|
let result: FindElementResult<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: FindElementResult<TElement> = {
|
|
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<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?: AnyPredicate<TElement>, def?: TElement) {
|
|
const result = this.#tryGetSingle(predicate);
|
|
|
|
return result.found ? result.element : def;
|
|
}
|
|
|
|
#tryElementAt(index: number): FindElementResult<TElement> {
|
|
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<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: AnyPredicate<number>, selector?: Converter<TElement, TResult>, comparer?: ComparisonOrComparer<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>;
|
|
}
|
|
|
|
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<TElement>) {
|
|
return this.#find(x => x > 0, undefined, comparer);
|
|
}
|
|
|
|
minBy<TBy>(converter: Converter<TElement, TBy>, comparer?: ComparisonOrComparer<TBy>) {
|
|
return this.#find(x => x > 0, converter, comparer);
|
|
}
|
|
|
|
max(comparer?: ComparisonOrComparer<TElement>) {
|
|
return this.#find(x => x < 0, undefined, comparer);
|
|
}
|
|
|
|
maxBy<TBy>(converter: Converter<TElement, TBy>, comparer?: ComparisonOrComparer<TBy>) {
|
|
return this.#find(x => x < 0, converter, comparer);
|
|
}
|
|
|
|
#findBounds<TResult>(selector?: Converter<TElement, TResult>, comparer?: ComparisonOrComparer<TResult>): [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<TElement, TResult>;
|
|
}
|
|
|
|
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<TElement>) {
|
|
return this.#findBounds(undefined, comparer);
|
|
}
|
|
|
|
boundsBy<TBy>(converter: Converter<TElement, TBy>, comparer?: ComparisonOrComparer<TBy>) {
|
|
return this.#findBounds(converter, comparer);
|
|
}
|
|
|
|
order(comparer?: ComparisonOrComparer<TElement>): OrderedSequence<TElement> {
|
|
return new OrderSequence<TElement>(this, false, comparer);
|
|
}
|
|
|
|
orderBy<TBy>(selector: Converter<TElement, TBy>, comparer?: ComparisonOrComparer<TBy>): OrderedSequence<TElement> {
|
|
return new OrderBySequence<TElement, TBy>(this, false, selector, comparer);
|
|
}
|
|
|
|
orderDescending(comparer?: ComparisonOrComparer<TElement>): OrderedSequence<TElement> {
|
|
return new OrderSequence<TElement>(this, true, comparer);
|
|
}
|
|
|
|
orderByDescending<TBy>(selector: Converter<TElement, TBy>, comparer?: ComparisonOrComparer<TBy>): OrderedSequence<TElement> {
|
|
return new OrderBySequence<TElement, TBy>(this, true, selector, comparer);
|
|
}
|
|
|
|
partition(equater?: EqualityComparisonOrComparer<TElement>): Sequence<Sequence<TElement>> {
|
|
return new PartitionSequence<TElement>(this, equater);
|
|
}
|
|
|
|
partitionBy<TBy>(selector: Converter<TElement, TBy>, equater?: EqualityComparisonOrComparer<TBy>): Sequence<Sequence<TElement>> {
|
|
return new PartitionBySequence<TElement, TBy>(this, selector, equater);
|
|
}
|
|
|
|
distinct(equater?: EqualityComparisonOrComparer<TElement>): Sequence<TElement> {
|
|
return new DistinctSequence<TElement>(this, equater);
|
|
}
|
|
|
|
distinctBy<TBy>(selector: Converter<TElement, TBy>, equater?: EqualityComparisonOrComparer<TBy>): Sequence<TElement> {
|
|
return new DistinctBySequence<TElement, TBy>(this, selector, equater);
|
|
}
|
|
|
|
union(sequence: Iterable<TElement>, equater?: EqualityComparisonOrComparer<TElement>): Sequence<TElement> {
|
|
return new UnionSequence<TElement>(this, wrap(sequence), equater);
|
|
}
|
|
|
|
unionBy<TBy>(sequence: Iterable<TElement>, selector: Converter<TElement, TBy>, equater?: EqualityComparisonOrComparer<TBy>): Sequence<TElement> {
|
|
return new UnionBySequence<TElement, TBy>(this, wrap(sequence), selector, equater);
|
|
}
|
|
|
|
except(sequence: Iterable<TElement>): Sequence<TElement> {
|
|
return new ExceptSequence<TElement>(this, wrap(sequence));
|
|
}
|
|
|
|
exceptBy<TBy>(sequence: Iterable<TElement>, selector: Converter<TElement, TBy>): Sequence<TElement> {
|
|
return new ExceptBySequence<TElement, TBy>(this, wrap(sequence), selector);
|
|
}
|
|
|
|
intersect(sequence: Iterable<TElement>): Sequence<TElement> {
|
|
return new IntersectSequence<TElement>(this, wrap(sequence));
|
|
}
|
|
|
|
intersectBy<TBy>(sequence: Iterable<TElement>, selector: Converter<TElement, TBy>): Sequence<TElement> {
|
|
return new IntersectBySequence<TElement, TBy>(this, wrap(sequence), selector);
|
|
}
|
|
|
|
all(predicate: AnyPredicate<TElement>) {
|
|
const n = this.nonEnumeratedCount();
|
|
|
|
if (n === 0) {
|
|
return false;
|
|
}
|
|
|
|
for (const element of this) {
|
|
if (!predicate(element)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
any(predicate?: AnyPredicate<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?: AnyPredicate<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: AnyPredicate<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: AnyPredicate<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>(sequence: Iterable<TOther>): Sequence<[TElement, TOther]> {
|
|
return new ZippedSequence<TElement, TOther>(this, wrap(sequence));
|
|
}
|
|
|
|
cartesianProduct<TOther>(sequence: Iterable<TOther>): Sequence<[TElement, TOther]> {
|
|
return new CartesianProductSequence<TElement, TOther>(this, wrap(sequence));
|
|
}
|
|
|
|
indexed(): Sequence<[number, TElement]> {
|
|
return new IndexedSequence<TElement>(this);
|
|
}
|
|
|
|
reversed(): Sequence<TElement> {
|
|
return new ReversedSequence<TElement>(this);
|
|
}
|
|
|
|
chunked(size: number): Sequence<Sequence<TElement>>;
|
|
chunked(size: number, asArray: true): Sequence<TElement[]>;
|
|
chunked<TResult>(size: number, transformer: SequencePipeline<TElement, TResult>): Sequence<TResult>;
|
|
chunked<TResult>(size: number, transformerOrAsArray?: true | SequencePipeline<TElement, TResult>): Sequence<Sequence<TElement>> | Sequence<TElement[]> | Sequence<TResult> {
|
|
if (size <= 0) {
|
|
throw new Error("Chunk size must be positive.");
|
|
}
|
|
|
|
if (transformerOrAsArray === true) {
|
|
return new ChunkedArraySequence<TElement>(this, size);
|
|
}
|
|
|
|
const result = new ChunkedSequence<TElement>(this, size);
|
|
return transformerOrAsArray ? result.select(transformerOrAsArray) : result;
|
|
}
|
|
|
|
random(options?: RandomOptions<TElement>) {
|
|
return getRandomElement(this, options).element;
|
|
}
|
|
|
|
cached(): Sequence<TElement> {
|
|
return new CacheSequence<TElement>(this);
|
|
}
|
|
|
|
awaited(): AsyncSequence<Awaited<TElement>> {
|
|
return new AwaitedSequence<TElement>(this);
|
|
}
|
|
|
|
asArray() {
|
|
return this.toArray();
|
|
}
|
|
|
|
toArray() {
|
|
return Array.from(this);
|
|
}
|
|
|
|
toMap<TKey>(keySelector: Converter<TElement, TKey>): Map<TKey, TElement>;
|
|
toMap<TKey, TValue>(keySelector: Converter<TElement, TKey>, valueSelector: Converter<TElement, TValue>): Map<TKey, TValue>;
|
|
toMap<TKey>(keySelector: Converter<TElement, TKey>, valueSelector?: Converter<TElement, any>): Map<TKey, any> {
|
|
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<TKey extends PropertyKey>(keySelector: Converter<TElement, TKey>): Record<TKey, TElement>;
|
|
toObject<TKey extends PropertyKey, TValue>(keySelector: Converter<TElement, TKey>, valueSelector: Converter<TElement, TValue>): Record<TKey, TValue>;
|
|
toObject<TKey extends PropertyKey>(keySelector: Converter<TElement, TKey>, valueSelector?: Converter<TElement, any>): Record<TKey, any> {
|
|
valueSelector ??= identity;
|
|
|
|
const obj: Record<PropertyKey, any> = {};
|
|
|
|
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();
|
|
}
|
|
|
|
toJSON() {
|
|
return this.#sequence.toJSON();
|
|
}
|
|
|
|
iterator() {
|
|
return this.#sequence.iterator();
|
|
}
|
|
|
|
apply<TResult>(pipeline: (sequence: Sequence<TElement>) => TResult) {
|
|
return this.#sequence.apply(pipeline);
|
|
}
|
|
|
|
count(predicate?: AnyPredicate<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: TypePredicate<TElement, TFiltered>): Sequence<TFiltered>;
|
|
where(predicate: AnyPredicate<TElement>): Sequence<TElement>;
|
|
where(predicate: any): Sequence<any> {
|
|
return this.#sequence.where(predicate);
|
|
}
|
|
|
|
groupBy<TKey>(keySelector: Converter<TElement, TKey>, elementSelector?: undefined, keyComparer?: EqualityComparisonOrComparer<TKey> | undefined): Sequence<GroupedSequence<TKey, TElement>>;
|
|
groupBy<TKey, TResult>(keySelector: Converter<TElement, TKey>, elementSelector: Converter<TElement, TResult>, keyComparer?: EqualityComparisonOrComparer<TKey> | undefined): Sequence<GroupedSequence<TKey, TResult>>;
|
|
groupBy(keySelector: any, elementSelector?: any, keyComparer?: any) {
|
|
return this.#sequence.groupBy(keySelector, elementSelector, keyComparer);
|
|
}
|
|
|
|
join<TOther, TKey>(sequence: Iterable<TOther>, firstKeySelector: Converter<TElement, TKey>, secondKeySelector: Converter<TOther, TKey>, resultSelector?: undefined, keyComparer?: EqualityComparisonOrComparer<TKey> | undefined): Sequence<[TElement, TOther]>;
|
|
join<TOther, TKey, TResult>(sequence: Iterable<TOther>, firstKeySelector: Converter<TElement, TKey>, secondKeySelector: Converter<TOther, TKey>, resultSelector: BiConverter<TElement, TOther, TResult>, keyComparer?: EqualityComparisonOrComparer<TKey> | undefined): Sequence<TResult>;
|
|
join(sequence: any, firstKeySelector: any, secondKeySelector: any, resultSelector?: any, keyComparer?: any) {
|
|
return this.#sequence.join(sequence, firstKeySelector, secondKeySelector, resultSelector, keyComparer);
|
|
}
|
|
|
|
groupJoin<TOther, TKey>(sequence: Iterable<TOther>, firstKeySelector: Converter<TElement, TKey>, secondKeySelector: Converter<TOther, TKey>, resultSelector?: undefined, keyComparer?: EqualityComparisonOrComparer<TKey> | undefined): Sequence<GroupedSequence<TElement, TOther>>;
|
|
groupJoin<TOther, TKey, TResult>(sequence: Iterable<TOther>, firstKeySelector: Converter<TElement, TKey>, secondKeySelector: Converter<TOther, TKey>, resultSelector: BiConverter<TElement, Iterable<TOther>, TResult>, keyComparer?: EqualityComparisonOrComparer<TKey> | undefined): Sequence<TResult>;
|
|
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<TElement>) {
|
|
return this.#sequence.contains(obj, equater);
|
|
}
|
|
|
|
sequenceEquals(sequence: Iterable<TElement>, equater?: EqualityComparisonOrComparer<TElement>) {
|
|
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<TElement>) {
|
|
return this.#sequence.remove(obj, all, equater);
|
|
}
|
|
|
|
concat(...sequences: Iterable<TElement>[]) {
|
|
return this.#sequence.concat(...sequences);
|
|
}
|
|
|
|
first(predicate?: AnyPredicate<TElement>) {
|
|
return this.#sequence.first(predicate);
|
|
}
|
|
|
|
firstOrDefault(predicate?: AnyPredicate<TElement>, def?: TElement) {
|
|
return this.#sequence.firstOrDefault(predicate, def);
|
|
}
|
|
|
|
last(predicate?: AnyPredicate<TElement>) {
|
|
return this.#sequence.last(predicate);
|
|
}
|
|
|
|
lastOrDefault(predicate?: AnyPredicate<TElement>, def?: TElement) {
|
|
return this.#sequence.lastOrDefault(predicate, def);
|
|
}
|
|
|
|
single(predicate?: AnyPredicate<TElement>) {
|
|
return this.#sequence.single(predicate);
|
|
}
|
|
|
|
singleOrDefault(predicate?: AnyPredicate<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?: ComparisonOrComparer<TElement>) {
|
|
return this.#sequence.min(comparer);
|
|
}
|
|
|
|
minBy<TBy>(selector: Converter<TElement, TBy>, comparer?: ComparisonOrComparer<TBy>) {
|
|
return this.#sequence.minBy(selector, comparer);
|
|
}
|
|
|
|
max(comparer?: ComparisonOrComparer<TElement>) {
|
|
return this.#sequence.max(comparer);
|
|
}
|
|
|
|
maxBy<TBy>(selector: Converter<TElement, TBy>, comparer?: ComparisonOrComparer<TBy>) {
|
|
return this.#sequence.maxBy(selector, comparer);
|
|
}
|
|
|
|
bounds(comparer?: ComparisonOrComparer<TElement>) {
|
|
return this.#sequence.bounds(comparer);
|
|
}
|
|
|
|
boundsBy<TBy>(selector: Converter<TElement, TBy>, comparer?: ComparisonOrComparer<TBy>) {
|
|
return this.#sequence.boundsBy(selector, comparer);
|
|
}
|
|
|
|
order(comparer?: ComparisonOrComparer<TElement>) {
|
|
return this.#sequence.order(comparer);
|
|
}
|
|
|
|
orderBy<TBy>(selector: Converter<TElement, TBy>, comparer?: ComparisonOrComparer<TBy>) {
|
|
return this.#sequence.orderBy(selector, comparer);
|
|
}
|
|
|
|
orderDescending(comparer?: ComparisonOrComparer<TElement>) {
|
|
return this.#sequence.orderDescending(comparer);
|
|
}
|
|
|
|
orderByDescending<TBy>(selector: Converter<TElement, TBy>, comparer?: ComparisonOrComparer<TBy>) {
|
|
return this.#sequence.orderByDescending(selector, comparer);
|
|
}
|
|
|
|
partition(equater?: EqualityComparisonOrComparer<TElement> | undefined): Sequence<Sequence<TElement>> {
|
|
return this.#sequence.partition(equater);
|
|
}
|
|
|
|
partitionBy<TBy>(selector: Converter<TElement, TBy>, equater?: EqualityComparisonOrComparer<TBy> | undefined): Sequence<Sequence<TElement>> {
|
|
return this.#sequence.partitionBy(selector, equater);
|
|
}
|
|
|
|
distinct(equater?: EqualityComparisonOrComparer<TElement>) {
|
|
return this.#sequence.distinct(equater);
|
|
}
|
|
|
|
distinctBy<TBy>(selector: Converter<TElement, TBy>, equater?: EqualityComparisonOrComparer<TBy>) {
|
|
return this.#sequence.distinctBy(selector, equater);
|
|
}
|
|
|
|
union(sequence: Iterable<TElement>, equater?: EqualityComparisonOrComparer<TElement>) {
|
|
return this.#sequence.union(sequence, equater);
|
|
}
|
|
|
|
unionBy<TBy>(sequence: Iterable<TElement>, selector: Converter<TElement, TBy>, equater?: EqualityComparisonOrComparer<TBy>) {
|
|
return this.#sequence.unionBy(sequence, selector, equater);
|
|
}
|
|
|
|
except(sequence: Iterable<TElement>, equater?: EqualityComparisonOrComparer<TElement>) {
|
|
return this.#sequence.except(sequence, equater);
|
|
}
|
|
|
|
exceptBy<TBy>(sequence: Iterable<TElement>, selector: Converter<TElement, TBy>, equater?: EqualityComparisonOrComparer<TBy>) {
|
|
return this.#sequence.exceptBy(sequence, selector, equater);
|
|
}
|
|
|
|
intersect(sequence: Iterable<TElement>, equater?: EqualityComparisonOrComparer<TElement>) {
|
|
return this.#sequence.intersect(sequence, equater);
|
|
}
|
|
|
|
intersectBy<TBy>(sequence: Iterable<TElement>, selector: Converter<TElement, TBy>, equater?: EqualityComparisonOrComparer<TBy>) {
|
|
return this.#sequence.intersectBy(sequence, selector, equater);
|
|
}
|
|
|
|
all(predicate: AnyPredicate<TElement>) {
|
|
return this.#sequence.all(predicate);
|
|
}
|
|
|
|
any(predicate: AnyPredicate<TElement>): boolean;
|
|
any(): boolean;
|
|
any(predicate?: any) {
|
|
return this.#sequence.any(predicate);
|
|
}
|
|
|
|
none(predicate: AnyPredicate<TElement>): 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<TElement>) {
|
|
return this.#sequence.skipWhile(condition);
|
|
}
|
|
|
|
take(n: number) {
|
|
return this.#sequence.take(n);
|
|
}
|
|
|
|
takeLast(n: number) {
|
|
return this.#sequence.takeLast(n);
|
|
}
|
|
|
|
takeWhile(condition: AnyPredicate<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>(sequence: Iterable<TOther>) {
|
|
return this.#sequence.zip(sequence);
|
|
}
|
|
|
|
cartesianProduct<TOther>(sequence: Iterable<TOther>) {
|
|
return this.#sequence.cartesianProduct(sequence);
|
|
}
|
|
|
|
indexed() {
|
|
return this.#sequence.indexed();
|
|
}
|
|
|
|
reversed() {
|
|
return this.#sequence.reversed();
|
|
}
|
|
|
|
chunked(size: number): Sequence<Sequence<TElement>>;
|
|
chunked(size: number, asArray: true): Sequence<TElement[]>;
|
|
chunked<TResult>(size: number, transformer: SequencePipeline<TElement, TResult>): Sequence<TResult>;
|
|
chunked(size: number, transformerOrAsArray?: any): any {
|
|
return this.#sequence.chunked(size, transformerOrAsArray);
|
|
}
|
|
|
|
random(options?: RandomOptions<TElement>) {
|
|
return this.#sequence.random(options);
|
|
}
|
|
|
|
cached() {
|
|
return this.#sequence.cached();
|
|
}
|
|
|
|
awaited(): AsyncSequence<Awaited<TElement>> {
|
|
return this.#sequence.awaited();
|
|
}
|
|
|
|
asArray() {
|
|
return this.#sequence.asArray();
|
|
}
|
|
|
|
toArray() {
|
|
return this.#sequence.toArray();
|
|
}
|
|
|
|
toMap<TKey>(keySelector: Converter<TElement, TKey>): Map<TKey, TElement>;
|
|
toMap<TKey, TValue>(keySelector: Converter<TElement, TKey>, valueSelector: Converter<TElement, TValue>): Map<TKey, TValue>;
|
|
toMap(keySelector: any, valueSelector?: any) {
|
|
return this.#sequence.toMap(keySelector, valueSelector);
|
|
}
|
|
|
|
toSet() {
|
|
return this.#sequence.toSet();
|
|
}
|
|
|
|
toObject<TKey extends PropertyKey>(keySelector: Converter<TElement, TKey>): Record<TKey, TElement>;
|
|
toObject<TKey extends PropertyKey, TValue>(keySelector: Converter<TElement, TKey>, valueSelector: Converter<TElement, TValue>): Record<TKey, TValue>;
|
|
toObject(keySelector: any, valueSelector?: any) {
|
|
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;
|
|
}
|
|
|
|
override toJSON() {
|
|
return { key: this.#key, items: this.toArray() };
|
|
}
|
|
}
|
|
|
|
export abstract class BaseOrderedSequence<TElement> extends BaseSequence<TElement> implements OrderedSequence<TElement> {
|
|
readonly #sequence: Sequence<TElement>;
|
|
readonly #sorter: Comparer<TElement>;
|
|
readonly #descending: boolean;
|
|
|
|
constructor(sequence: Sequence<TElement>, sorter: ComparisonOrComparer<TElement> | 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<TElement>): OrderedSequence<TElement> {
|
|
return new ThenOrderSequence(this, false, comparer);
|
|
}
|
|
|
|
thenBy<TBy>(selector: Converter<TElement, TBy>, comparer?: ComparisonOrComparer<TBy>): OrderedSequence<TElement> {
|
|
return new ThenOrderBySequence<TElement, TBy>(this, false, selector, comparer);
|
|
}
|
|
|
|
thenSelfDescending(comparer?: ComparisonOrComparer<TElement>): OrderedSequence<TElement> {
|
|
return new ThenOrderSequence(this, true, comparer);
|
|
}
|
|
|
|
thenByDescending<TBy>(selector: Converter<TElement, TBy>, comparer?: ComparisonOrComparer<TBy>): OrderedSequence<TElement> {
|
|
return new ThenOrderBySequence<TElement, TBy>(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<T> extends BaseSequence<T> {
|
|
override nonEnumeratedCount() {
|
|
return 0;
|
|
}
|
|
|
|
override *iterator() { }
|
|
}
|
|
|
|
export const EMPTY = new EmptySequence<any>();
|
|
|
|
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: ReadonlyArray<T>;
|
|
|
|
constructor(array: ReadonlyArray<T>) {
|
|
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<T>): 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<T>) {
|
|
return this.#array.every(predicate);
|
|
}
|
|
|
|
override any(predicate?: AnyPredicate<T>) {
|
|
if (predicate) {
|
|
return this.#array.some(predicate);
|
|
}
|
|
|
|
return this.#array.length > 0;
|
|
}
|
|
|
|
override none(predicate?: AnyPredicate<T>) {
|
|
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<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: ReadonlySet<T>;
|
|
|
|
constructor(set: ReadonlySet<T>) {
|
|
super();
|
|
|
|
this.#set = set;
|
|
}
|
|
|
|
override nonEnumeratedCount() {
|
|
return this.#set.size;
|
|
}
|
|
|
|
override maxCount() {
|
|
return this.#set.size;
|
|
}
|
|
|
|
override contains(obj: T, equater?: EqualityComparisonOrComparer<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: ReadonlyMap<K, V>;
|
|
|
|
constructor(map: ReadonlyMap<K, V>) {
|
|
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<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;
|
|
}
|
|
}
|
|
}
|
|
|
|
class DistinctSequence<T> extends BaseSequence<T> {
|
|
readonly #sequence: Sequence<T>;
|
|
readonly #equater: EqualityComparisonOrComparer<T> | undefined;
|
|
|
|
constructor(sequence: Sequence<T>, equater?: EqualityComparisonOrComparer<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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class DistinctBySequence<T, U> extends BaseSequence<T> {
|
|
readonly #sequence: Sequence<T>;
|
|
readonly #converter: Converter<T, U>;
|
|
readonly #equater: EqualityComparisonOrComparer<U> | undefined;
|
|
|
|
constructor(sequence: Sequence<T>, converter: Converter<T, U>, equater?: EqualityComparisonOrComparer<U>) {
|
|
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<TElement, TFiltered extends TElement> extends BaseSequence<TFiltered> {
|
|
readonly #sequence: Sequence<TElement>;
|
|
readonly #predicate: TypePredicate<TElement, TFiltered>;
|
|
|
|
constructor(sequence: Sequence<TElement>, predicate: TypePredicate<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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
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];
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
class SkipWhileSequence<T> extends BaseSequence<T> {
|
|
readonly #sequence: Sequence<T>;
|
|
readonly #predicate: AnyPredicate<T>;
|
|
|
|
constructor(sequence: Sequence<T>, predicate: AnyPredicate<T>) {
|
|
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<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 = Iterator.from(this.#sequence);
|
|
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 iterator) {
|
|
yield buffer[i];
|
|
buffer[i] = obj;
|
|
i = (i + 1) % this.#n;
|
|
}
|
|
}
|
|
}
|
|
|
|
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 = Iterator.from(this.#sequence);
|
|
let i = 0;
|
|
|
|
do {
|
|
if (iterator.next().done) {
|
|
return;
|
|
}
|
|
|
|
i++;
|
|
} while (i < this.#n);
|
|
|
|
yield* iterator;
|
|
}
|
|
}
|
|
|
|
class TakeWhileSequence<T> extends BaseSequence<T> {
|
|
readonly #sequence: Sequence<T>;
|
|
readonly #predicate: AnyPredicate<T>;
|
|
|
|
constructor(sequence: Sequence<T>, predicate: AnyPredicate<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;
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
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--;
|
|
}
|
|
}
|
|
}
|
|
|
|
class OrderSequence<T> extends BaseOrderedSequence<T> {
|
|
constructor(sequence: Sequence<T>, descending: boolean, sorter?: ComparisonOrComparer<T>) {
|
|
super(sequence, sorter, descending);
|
|
}
|
|
}
|
|
|
|
class OrderBySequence<T, U> extends BaseOrderedSequence<T> {
|
|
constructor(sequence: Sequence<T>, descending: boolean, selector: Converter<T, U>, sorter?: ComparisonOrComparer<U>) {
|
|
super(sequence, createComparerUsing(selector, sorter), descending);
|
|
}
|
|
}
|
|
|
|
class ThenOrderSequence<T> extends BaseOrderedSequence<T> {
|
|
constructor(sequence: OrderedSequence<T>, descending: boolean, sorter?: ComparisonOrComparer<T>) {
|
|
super(sequence, combineComparers([sequence.comparer, sorter]), descending);
|
|
}
|
|
}
|
|
|
|
class ThenOrderBySequence<T, U> extends BaseOrderedSequence<T> {
|
|
constructor(sequence: OrderedSequence<T>, descending: boolean, selector: Converter<T, U>, sorter?: ComparisonOrComparer<U>) {
|
|
super(sequence, combineComparers([sequence.comparer, createComparerUsing(selector, sorter)]), descending);
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
class PeekSequence<T> extends BaseSequence<T> {
|
|
readonly #sequence: Sequence<T>;
|
|
readonly #action: Action<T>;
|
|
|
|
constructor(sequence: Sequence<T>, action: Action<T>) {
|
|
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<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 CartesianProductSequence<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 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<T> extends BaseSequence<T> {
|
|
readonly #first: Sequence<T>;
|
|
readonly #second: Sequence<T>;
|
|
readonly #equater: EqualityComparisonOrComparer<T> | undefined;
|
|
|
|
constructor(first: Sequence<T>, second: Sequence<T>, equater?: EqualityComparisonOrComparer<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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class UnionBySequence<T, U> extends BaseSequence<T> {
|
|
readonly #first: Sequence<T>;
|
|
readonly #second: Sequence<T>;
|
|
readonly #selector: Converter<T, U>;
|
|
readonly #equater: EqualityComparisonOrComparer<U> | undefined;
|
|
|
|
constructor(first: Sequence<T>, second: Sequence<T>, selector: Converter<T, U>, equater?: EqualityComparisonOrComparer<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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class ExceptSequence<T> extends BaseSequence<T> {
|
|
readonly #first: Sequence<T>;
|
|
readonly #second: Sequence<T>;
|
|
readonly #equater: EqualityComparisonOrComparer<T> | undefined;
|
|
|
|
constructor(first: Sequence<T>, second: Sequence<T>, equater?: EqualityComparisonOrComparer<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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class ExceptBySequence<T, U> extends BaseSequence<T> {
|
|
readonly #first: Sequence<T>;
|
|
readonly #second: Sequence<T>;
|
|
readonly #selector: Converter<T, U>;
|
|
readonly #equater: EqualityComparisonOrComparer<U> | undefined;
|
|
|
|
constructor(first: Sequence<T>, second: Sequence<T>, selector: Converter<T, U>, equater?: EqualityComparisonOrComparer<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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class IntersectSequence<T> extends BaseSequence<T> {
|
|
readonly #first: Sequence<T>;
|
|
readonly #second: Sequence<T>;
|
|
readonly #equater: EqualityComparisonOrComparer<T> | undefined;
|
|
|
|
constructor(first: Sequence<T>, second: Sequence<T>, equater?: EqualityComparisonOrComparer<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);
|
|
|
|
set.addAll(this.#second);
|
|
|
|
for (const obj of this.#first) {
|
|
if (set.remove(obj)) {
|
|
yield obj;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class IntersectBySequence<T, U> extends BaseSequence<T> {
|
|
readonly #first: Sequence<T>;
|
|
readonly #second: Sequence<T>;
|
|
readonly #selector: Converter<T, U>;
|
|
readonly #equater: EqualityComparisonOrComparer<U> | undefined;
|
|
|
|
constructor(first: Sequence<T>, second: Sequence<T>, selector: Converter<T, U>, equater?: EqualityComparisonOrComparer<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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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()!;
|
|
}
|
|
}
|
|
}
|
|
|
|
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 #keyEquater: EqualityComparisonOrComparer<TKey> | undefined;
|
|
|
|
constructor(sequence: Sequence<TElement>, keySelector: Converter<TElement, TKey>, elementSelector?: Converter<TElement, TResult>, keyEquater?: EqualityComparisonOrComparer<TKey>) {
|
|
super();
|
|
|
|
this.#sequence = sequence;
|
|
this.#keySelector = keySelector;
|
|
this.#elementSelector = elementSelector ?? identity as Converter<TElement, TResult>;
|
|
this.#keyEquater = keyEquater;
|
|
}
|
|
|
|
override maxCount() {
|
|
return this.#sequence.maxCount();
|
|
}
|
|
|
|
override *iterator() {
|
|
const groupings = createEqualityMap<TKey, TResult[]>(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<T> extends BaseSequence<Sequence<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 array(chunk);
|
|
chunk = [];
|
|
}
|
|
}
|
|
|
|
if (chunk.length > 0) {
|
|
yield array(chunk);
|
|
}
|
|
}
|
|
}
|
|
|
|
class ChunkedArraySequence<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;
|
|
}
|
|
}
|
|
}
|
|
|
|
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 #keyEquater: EqualityComparer<TKey>;
|
|
|
|
constructor(first: Sequence<TOuter>, second: Sequence<TInner>, firstKeySelector: Converter<TOuter, TKey>, secondKeySelector: Converter<TInner, TKey>, resultSelector?: BiConverter<TOuter, TInner, TResult>, keyEquater?: EqualityComparisonOrComparer<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.#keyEquater = keyEquater ? asEqualityComparer(keyEquater) : defaultEqualityComparer;
|
|
}
|
|
|
|
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.#keyEquater.equals(firstKey, secondKey)) {
|
|
yield this.#resultSelector(firstObj, secondObj);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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 #keyEquater: EqualityComparer<TKey>;
|
|
|
|
constructor(first: Sequence<TOuter>, second: Sequence<TInner>, firstKeySelector: Converter<TOuter, TKey>, secondKeySelector: Converter<TInner, TKey>, resultSelector?: BiConverter<TOuter, Sequence<TInner>, TResult>, keyEquater?: EqualityComparisonOrComparer<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.#keyEquater = keyEquater ? asEqualityComparer(keyEquater) : defaultEqualityComparer;
|
|
}
|
|
|
|
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.#keyEquater.equals(firstKey, secondKey)) {
|
|
secondObjs.push(secondObj);
|
|
}
|
|
}
|
|
|
|
yield this.#resultSelector(firstObj, array(secondObjs));
|
|
}
|
|
}
|
|
}
|
|
|
|
class RemoveSequence<T> extends BaseSequence<T> {
|
|
readonly #sequence: Sequence<T>;
|
|
readonly #obj: T;
|
|
readonly #all: boolean;
|
|
readonly #equater: EqualityComparer<T>;
|
|
|
|
constructor(sequence: Sequence<T>, obj: T, all?: boolean, equater?: EqualityComparisonOrComparer<T>) {
|
|
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<T> extends BaseSequence<T> {
|
|
readonly #sequence: Sequence<T>;
|
|
#cache: T[] | undefined;
|
|
|
|
constructor(sequence: Sequence<T>) {
|
|
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<T> extends BaseSequence<Sequence<T>> {
|
|
readonly #sequence: Sequence<T>;
|
|
readonly #equater: EqualityComparisonOrComparer<T> | undefined;
|
|
|
|
constructor(sequence: Sequence<T>, equater: EqualityComparisonOrComparer<T> | undefined) {
|
|
super();
|
|
|
|
this.#sequence = sequence;
|
|
this.#equater = equater;
|
|
}
|
|
|
|
override *iterator() {
|
|
const partitions = createEqualityMap<T, T[]>(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<TElement, TBy> extends BaseSequence<Sequence<TElement>> {
|
|
readonly #sequence: Sequence<TElement>;
|
|
readonly #selector: Converter<TElement, TBy>;
|
|
readonly #equater: EqualityComparisonOrComparer<TBy> | undefined;
|
|
|
|
constructor(sequence: Sequence<TElement>, selector: Converter<TElement, TBy>, equater: EqualityComparisonOrComparer<TBy> | undefined) {
|
|
super();
|
|
|
|
this.#sequence = sequence;
|
|
this.#selector = selector;
|
|
this.#equater = equater;
|
|
}
|
|
|
|
override *iterator() {
|
|
const partitions = createEqualityMap<TBy, TElement[]>(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<T> extends BaseAsyncSequence<Awaited<T>> {
|
|
readonly #sequence: Sequence<T>;
|
|
|
|
constructor(sequence: Sequence<T>) {
|
|
super();
|
|
|
|
this.#sequence = sequence;
|
|
}
|
|
|
|
override async *iterator() {
|
|
yield* this.#sequence;
|
|
}
|
|
}
|