1
0

harmonize sync and async implementations

This commit is contained in:
2024-05-09 17:35:55 +02:00
parent a1f43287a0
commit 6c0713d591
4 changed files with 607 additions and 289 deletions

View File

@@ -1,4 +1,4 @@
import { Accumulator, Action, BiConverter, Comparer, Converter, Enumerable, Equater, Predicate, wrap as wrapSync } from "./sync.js";
import { Accumulator, Action, BiConverter, Comparer, Converter, Enumerable, Equater, Predicate } from "./sync.js";
import { AsyncFunction, MaybeAsyncFunction, MaybePromise, asAsyncGenerator, combineAsyncComparers, defaultArrayComparer, identity, isAsyncIterable, operatorCompare, strictEquals } from "./utils.js";
import { createQueue } from "./queue.js";
import { selectionSorter } from "./sorting.js";
@@ -33,11 +33,12 @@ export type MaybeAsyncEquater<T> = MaybeAsyncFunction<Equater<T>>;
export interface AsyncEnumerable<TElement> extends AsyncIterable<TElement> {
iterator(): AsyncIterator<TElement>;
apply<TResult>(pipeline: (enumerable: this) => TResult): TResult;
apply<TResult>(pipeline: (enumerable: AsyncEnumerable<TElement>) => TResult): TResult;
count(predicate?: MaybeAsyncPredicate<TElement>): Promise<number>;
nonEnumeratedCount(): Promise<number>;
fastCount(): Promise<number>;
maxCount(): Promise<number>;
select<TResult>(selector: MaybeAsyncConverter<TElement, TResult>): AsyncEnumerable<TResult>;
selectMany<TResult>(selector: MaybeAsyncConverter<TElement, MaybeAsyncIterable<TResult>>): AsyncEnumerable<TResult>;
@@ -55,7 +56,7 @@ export interface AsyncEnumerable<TElement> extends AsyncIterable<TElement> {
contains(obj: TElement, equater?: MaybeAsyncEquater<TElement>): Promise<boolean>;
sequenceEqual(iterable: MaybeAsyncIterable<TElement>, equater?: MaybeAsyncEquater<TElement>): Promise<boolean>;
sequenceEquals(iterable: MaybeAsyncIterable<TElement>, equater?: MaybeAsyncEquater<TElement>): Promise<boolean>;
append(obj: TElement): AsyncEnumerable<TElement>;
@@ -108,6 +109,8 @@ export interface AsyncEnumerable<TElement> extends AsyncIterable<TElement> {
all(predicate: MaybeAsyncPredicate<TElement>): Promise<boolean>;
any(predicate: MaybeAsyncPredicate<TElement>): Promise<boolean>;
any(): Promise<boolean>;
none(predicate: Predicate<TElement>): Promise<boolean>;
none(): Promise<boolean>;
skip(n: number): AsyncEnumerable<TElement>;
skipLast(n: number): AsyncEnumerable<TElement>;
@@ -123,18 +126,21 @@ export interface AsyncEnumerable<TElement> extends AsyncIterable<TElement> {
zip<TOther>(iterable: MaybeAsyncIterable<TOther>): AsyncEnumerable<[TElement, TOther]>;
index(): AsyncEnumerable<[number, TElement]>;
indexex(): AsyncEnumerable<[number, TElement]>;
reverse(): AsyncEnumerable<TElement>;
reversed(): AsyncEnumerable<TElement>;
chunk(size: number): AsyncEnumerable<TElement[]>;
chunked(size: number): AsyncEnumerable<TElement[]>;
cache(): AsyncEnumerable<TElement>;
// random(options?: RandomOptions<TElement>): TElement | undefined;
cached(): AsyncEnumerable<TElement>;
asArray(): Promise<TElement[]>;
toArray(): Promise<TElement[]>;
toMap<TKey, TValue>(keySelector: MaybeAsyncConverter<TElement, TKey>, valueSelector: MaybeAsyncConverter<TElement, TValue>): Promise<Map<TKey, TValue>>;
toSet(): Promise<Set<TElement>>;
toObject<TValue>(keySelector: MaybeAsyncConverter<TElement, PropertyKey>, valueSelector: MaybeAsyncConverter<TElement, TValue>): Promise<Record<PropertyKey, TValue>>;
toObject<TKey extends PropertyKey, TValue>(keySelector: MaybeAsyncConverter<TElement, TKey>, valueSelector: MaybeAsyncConverter<TElement, TValue>): Promise<Record<TKey, TValue>>;
collect<TResult>(collector: Collector<TElement, any, TResult>): Promise<TResult>;
}
@@ -159,6 +165,7 @@ export interface OrderedAsyncEnumerable<TElement> extends AsyncEnumerable<TEleme
//#region wrappers
export namespace AsyncEnumerable {
export function asAsync<T>(enumerable: Enumerable<T>): AsyncEnumerable<T> {
return new WrappedEnumerable(enumerable);
}
@@ -172,7 +179,7 @@ export function wrap<T>(iterable: MaybeAsyncIterable<T>): AsyncEnumerable<T> {
return sequence(iterable);
}
return asAsync(wrapSync(iterable));
return asAsync(Enumerable.wrap(iterable));
}
export function sequence<T>(iterable: AsyncIterable<T>): AsyncEnumerable<T> {
@@ -250,25 +257,8 @@ export function repeat<T>(value: T, count?: number): AsyncEnumerable<T> {
return new RepeatAsyncEnumerable(value, count);
}
export namespace sum {
export async function number(iterable: AsyncIterable<number>) {
let result = 0;
for await (const n of iterable) {
result += n;
}
return result;
}
export async function bigint(iterable: AsyncIterable<bigint>) {
let result = 0n;
for await (const n of iterable) {
result += n;
}
return result;
export function isAsyncEnumerable<T = any>(obj: any): obj is Enumerable<T> {
return obj instanceof AsyncEnumerableMarker;
}
}
@@ -276,14 +266,18 @@ export namespace sum {
//#region implementations
export abstract class BaseAsyncEnumerable<TElement> implements AsyncEnumerable<TElement> {
class AsyncEnumerableMarker {
}
export abstract class BaseAsyncEnumerable<TElement> extends AsyncEnumerableMarker implements AsyncEnumerable<TElement> {
[Symbol.asyncIterator]() {
return this.iterator();
}
abstract iterator(): AsyncIterator<TElement>;
apply<TResult>(pipeline: (enumerable: this) => TResult) {
apply<TResult>(pipeline: (enumerable: AsyncEnumerable<TElement>) => TResult): TResult {
return pipeline(this);
}
@@ -304,11 +298,11 @@ export abstract class BaseAsyncEnumerable<TElement> implements AsyncEnumerable<T
}
join<TOther, TKey, TResult>(iterable: MaybeAsyncIterable<TOther>, firstKeySelector: MaybeAsyncConverter<TElement, TKey>, secondKeySelector: MaybeAsyncConverter<TOther, TKey>, resultSelector?: MaybeAsyncBiConverter<TElement, TOther, TResult>, keyComparer?: MaybeAsyncEquater<TKey>): AsyncEnumerable<TResult> {
return new JoinAsyncEnumerable<TElement, TOther, TKey, TResult>(this, wrap(iterable), firstKeySelector, secondKeySelector, resultSelector, keyComparer);
return new JoinAsyncEnumerable<TElement, TOther, TKey, TResult>(this, AsyncEnumerable.wrap(iterable), firstKeySelector, secondKeySelector, resultSelector, keyComparer);
}
groupJoin<TOther, TKey, TResult>(iterable: MaybeAsyncIterable<TOther>, firstKeySelector: MaybeAsyncConverter<TElement, TKey>, secondKeySelector: MaybeAsyncConverter<TOther, TKey>, resultSelector?: MaybeAsyncBiConverter<TElement, AsyncEnumerable<TOther>, TResult>, keyComparer?: MaybeAsyncEquater<TKey>): AsyncEnumerable<TResult> {
return new GroupJoinAsyncEnumerable<TElement, TOther, TKey, TResult>(this, wrap(iterable), firstKeySelector, secondKeySelector, resultSelector, keyComparer);
return new GroupJoinAsyncEnumerable<TElement, TOther, TKey, TResult>(this, AsyncEnumerable.wrap(iterable), firstKeySelector, secondKeySelector, resultSelector, keyComparer);
}
async contains(obj: TElement, equater?: MaybeAsyncEquater<TElement>) {
@@ -325,12 +319,12 @@ export abstract class BaseAsyncEnumerable<TElement> implements AsyncEnumerable<T
return false;
}
async sequenceEqual(iterable: MaybeAsyncIterable<TElement>, equater?: MaybeAsyncEquater<TElement>) {
async sequenceEquals(iterable: MaybeAsyncIterable<TElement>, equater?: MaybeAsyncEquater<TElement>) {
if (this === iterable) {
return true;
}
const that = wrap(iterable);
const that = AsyncEnumerable.wrap(iterable);
const thisCount = await this.nonEnumeratedCount();
const thatCount = await that.nonEnumeratedCount();
@@ -351,7 +345,7 @@ export abstract class BaseAsyncEnumerable<TElement> implements AsyncEnumerable<T
const thatNext = await thatIterator.next();
if (thisNext.done) {
return thatNext.done === true; // no undefined!
return thatNext.done === true;
}
if (thatNext.done) {
@@ -384,7 +378,7 @@ export abstract class BaseAsyncEnumerable<TElement> implements AsyncEnumerable<T
const arr: AsyncEnumerable<TElement>[] = [this];
for (const iterable of iterables) {
arr.push(wrap(iterable));
arr.push(AsyncEnumerable.wrap(iterable));
}
return new ConcatAsyncEnumerable(arr);
@@ -419,6 +413,11 @@ export abstract class BaseAsyncEnumerable<TElement> implements AsyncEnumerable<T
return n >= 0 ? n : await this.count();
}
async maxCount() {
const n = await this.nonEnumeratedCount();
return n >= 0 ? n : Infinity;
}
async #tryGetFirst(predicate?: MaybeAsyncPredicate<TElement>) {
if (predicate) {
for await (const element of this) {
@@ -723,27 +722,27 @@ export abstract class BaseAsyncEnumerable<TElement> implements AsyncEnumerable<T
}
union(iterable: MaybeAsyncIterable<TElement>, equater?: MaybeAsyncEquater<TElement>): AsyncEnumerable<TElement> {
return new UnionAsyncEnumerable<TElement>(this, wrap(iterable), equater);
return new UnionAsyncEnumerable<TElement>(this, AsyncEnumerable.wrap(iterable), equater);
}
unionBy<TBy>(iterable: MaybeAsyncIterable<TElement>, selector: MaybeAsyncConverter<TElement, TBy>, equater?: MaybeAsyncEquater<TBy>): AsyncEnumerable<TElement> {
return new UnionByAsyncEnumerable<TElement, TBy>(this, wrap(iterable), selector, equater);
return new UnionByAsyncEnumerable<TElement, TBy>(this, AsyncEnumerable.wrap(iterable), selector, equater);
}
except(iterable: MaybeAsyncIterable<TElement>): AsyncEnumerable<TElement> {
return new ExceptAsyncEnumerable<TElement>(this, wrap(iterable));
return new ExceptAsyncEnumerable<TElement>(this, AsyncEnumerable.wrap(iterable));
}
exceptBy<TBy>(iterable: MaybeAsyncIterable<TElement>, selector: MaybeAsyncConverter<TElement, TBy>): AsyncEnumerable<TElement> {
return new ExceptByAsyncEnumerable<TElement, TBy>(this, wrap(iterable), selector);
return new ExceptByAsyncEnumerable<TElement, TBy>(this, AsyncEnumerable.wrap(iterable), selector);
}
intersect(iterable: MaybeAsyncIterable<TElement>): AsyncEnumerable<TElement> {
return new IntersectAsyncEnumerable<TElement>(this, wrap(iterable));
return new IntersectAsyncEnumerable<TElement>(this, AsyncEnumerable.wrap(iterable));
}
intersectBy<TBy>(iterable: MaybeAsyncIterable<TElement>, selector: MaybeAsyncConverter<TElement, TBy>): AsyncEnumerable<TElement> {
return new IntersectByAsyncEnumerable<TElement, TBy>(this, wrap(iterable), selector);
return new IntersectByAsyncEnumerable<TElement, TBy>(this, AsyncEnumerable.wrap(iterable), selector);
}
async all(predicate: MaybeAsyncPredicate<TElement>) {
@@ -782,6 +781,26 @@ export abstract class BaseAsyncEnumerable<TElement> implements AsyncEnumerable<T
return n < 0 ? !(await this.iterator().next()).done : n > 0;
}
async none(predicate?: MaybeAsyncPredicate<TElement>) {
const n = await this.nonEnumeratedCount();
if (n === 0) {
return true;
}
if (predicate) {
for await (const element of this) {
if (predicate(element)) {
return false;
}
}
return true;
}
return n < 0 && (await this.iterator().next()).done === true;
}
skip(n: number): AsyncEnumerable<TElement> {
if (n < 0) {
throw new Error("Cannot skip a negative number of elements.");
@@ -807,7 +826,7 @@ export abstract class BaseAsyncEnumerable<TElement> implements AsyncEnumerable<T
throw new Error("Cannot take a negative number of elements.");
}
return n === 0 ? empty<TElement>() : new TakeAsyncEnumerable<TElement>(this, n);
return n === 0 ? AsyncEnumerable.empty<TElement>() : new TakeAsyncEnumerable<TElement>(this, n);
}
takeLast(n: number): AsyncEnumerable<TElement> {
@@ -815,7 +834,7 @@ export abstract class BaseAsyncEnumerable<TElement> implements AsyncEnumerable<T
throw new Error("Cannot take a negative number of elements.");
}
return n === 0 ? empty<TElement>() : new TakeLastAsyncEnumerable<TElement>(this, n);
return n === 0 ? AsyncEnumerable.empty<TElement>() : new TakeLastAsyncEnumerable<TElement>(this, n);
}
takeWhile(predicate: MaybeAsyncPredicate<TElement>): AsyncEnumerable<TElement> {
@@ -833,18 +852,18 @@ export abstract class BaseAsyncEnumerable<TElement> implements AsyncEnumerable<T
}
zip<TOther>(iterable: MaybeAsyncIterable<TOther>): AsyncEnumerable<[TElement, TOther]> {
return new ZippedAsyncEnumerable<TElement, TOther>(this, wrap(iterable));
return new ZippedAsyncEnumerable<TElement, TOther>(this, AsyncEnumerable.wrap(iterable));
}
index(): AsyncEnumerable<[number, TElement]> {
indexex(): AsyncEnumerable<[number, TElement]> {
return new IndexedAsyncEnumerable<TElement>(this);
}
reverse(): AsyncEnumerable<TElement> {
reversed(): AsyncEnumerable<TElement> {
return new ReversedAsyncEnumerable<TElement>(this);
}
chunk(size: number): AsyncEnumerable<TElement[]> {
chunked(size: number): AsyncEnumerable<TElement[]> {
if (size <= 0) {
throw new Error("Chunk size must be positive.");
}
@@ -852,10 +871,14 @@ export abstract class BaseAsyncEnumerable<TElement> implements AsyncEnumerable<T
return new ChunkedAsyncEnumerable<TElement>(this, size);
}
cache(): AsyncEnumerable<TElement> {
cached(): AsyncEnumerable<TElement> {
return new CacheAsyncEnumerable<TElement>(this);
}
async asArray() {
return await this.toArray();
}
async toArray() {
const array: TElement[] = [];
@@ -913,28 +936,313 @@ export abstract class BaseAsyncEnumerable<TElement> implements AsyncEnumerable<T
}
}
class GroupedAsyncEnumerableImpl<TElement, TKey> extends BaseAsyncEnumerable<TElement> implements GroupedAsyncEnumerable<TKey, TElement> {
readonly #key: TKey;
readonly #grouping: AsyncEnumerable<TElement>;
class DelegatedAsyncEnumerable<TElement> extends AsyncEnumerableMarker implements AsyncEnumerable<TElement> {
#enumerable: AsyncEnumerable<TElement>;
constructor(key: TKey, grouping: AsyncEnumerable<TElement>) {
constructor(enumerable: AsyncEnumerable<TElement>) {
super();
this.#enumerable = enumerable;
}
get enumerable() {
return this.#enumerable;
}
protected set enumerable(value: AsyncEnumerable<TElement>) {
this.#enumerable = value;
}
[Symbol.asyncIterator]() {
return this.iterator();
}
iterator() {
return this.#enumerable.iterator();
}
apply<TResult>(pipeline: (enumerable: AsyncEnumerable<TElement>) => TResult) {
return this.#enumerable.apply(pipeline);
}
count(predicate?: ((obj: TElement) => MaybePromise<boolean>) | undefined): Promise<number> {
return this.#enumerable.count(predicate);
}
nonEnumeratedCount(): Promise<number> {
return this.#enumerable.nonEnumeratedCount();
}
fastCount(): Promise<number> {
return this.#enumerable.fastCount();
}
maxCount(): Promise<number> {
return this.#enumerable.maxCount();
}
select<TResult>(selector: (obj: TElement) => MaybePromise<TResult>): AsyncEnumerable<TResult> {
return this.#enumerable.select(selector);
}
selectMany<TResult>(selector: (obj: TElement) => MaybePromise<MaybeAsyncIterable<TResult>>): AsyncEnumerable<TResult> {
return this.#enumerable.selectMany(selector);
}
where(predicate: (obj: TElement) => MaybePromise<boolean>): AsyncEnumerable<TElement> {
return this.#enumerable.where(predicate);
}
groupBy<TKey>(keySelector: (obj: TElement) => MaybePromise<TKey>, elementSelector?: undefined, keyComparer?: ((first: TKey, second: TKey) => MaybePromise<boolean>) | undefined): AsyncEnumerable<GroupedAsyncEnumerable<TKey, TElement>>;
groupBy<TKey, TResult>(keySelector: (obj: TElement) => MaybePromise<TKey>, elementSelector: (obj: TElement) => MaybePromise<TResult>, keyComparer?: ((first: TKey, second: TKey) => MaybePromise<boolean>) | undefined): AsyncEnumerable<GroupedAsyncEnumerable<TKey, TResult>>;
groupBy(keySelector: any, elementSelector?: any, keyComparer?: any) {
return this.#enumerable.groupBy(keySelector, elementSelector, keyComparer);
}
join<TOther, TKey>(iterable: MaybeAsyncIterable<TOther>, firstKeySelector: (obj: TElement) => MaybePromise<TKey>, secondKeySelector: (obj: TOther) => MaybePromise<TKey>, resultSelector?: undefined, keyComparer?: ((first: TKey, second: TKey) => MaybePromise<boolean>) | undefined): AsyncEnumerable<[TElement, TOther]>;
join<TOther, TKey, TResult>(iterable: MaybeAsyncIterable<TOther>, firstKeySelector: (obj: TElement) => MaybePromise<TKey>, secondKeySelector: (obj: TOther) => MaybePromise<TKey>, resultSelector: (first: TElement, second: TOther) => MaybePromise<TResult>, keyComparer?: ((first: TKey, second: TKey) => MaybePromise<boolean>) | undefined): AsyncEnumerable<TResult>;
join(iterable: any, firstKeySelector: any, secondKeySelector: any, resultSelector?: any, keyComparer?: any) {
return this.#enumerable.join(iterable, firstKeySelector, secondKeySelector, resultSelector, keyComparer);
}
groupJoin<TOther, TKey>(iterable: MaybeAsyncIterable<TOther>, firstKeySelector: (obj: TElement) => MaybePromise<TKey>, secondKeySelector: (obj: TOther) => MaybePromise<TKey>, resultSelector?: undefined, keyComparer?: ((first: TKey, second: TKey) => MaybePromise<boolean>) | undefined): AsyncEnumerable<GroupedAsyncEnumerable<TElement, TOther>>;
groupJoin<TOther, TKey, TResult>(iterable: MaybeAsyncIterable<TOther>, firstKeySelector: (obj: TElement) => MaybePromise<TKey>, secondKeySelector: (obj: TOther) => MaybePromise<TKey>, resultSelector: (first: TElement, second: AsyncEnumerable<TOther>) => MaybePromise<TResult>, keyComparer?: ((first: TKey, second: TKey) => MaybePromise<boolean>) | undefined): AsyncEnumerable<TResult>;
groupJoin(iterable: any, firstKeySelector: any, secondKeySelector: any, resultSelector?: any, keyComparer?: any) {
return this.#enumerable.groupJoin(iterable, firstKeySelector, secondKeySelector, resultSelector, keyComparer);
}
contains(obj: TElement, equater?: ((first: TElement, second: TElement) => MaybePromise<boolean>) | undefined): Promise<boolean> {
return this.#enumerable.contains(obj, equater);
}
sequenceEquals(iterable: MaybeAsyncIterable<TElement>, equater?: ((first: TElement, second: TElement) => MaybePromise<boolean>) | undefined): Promise<boolean> {
return this.#enumerable.sequenceEquals(iterable, equater);
}
append(obj: TElement): AsyncEnumerable<TElement> {
return this.#enumerable.append(obj);
}
prepend(obj: TElement): AsyncEnumerable<TElement> {
return this.#enumerable.prepend(obj);
}
remove(obj: TElement, all?: boolean | undefined, equater?: ((first: TElement, second: TElement) => MaybePromise<boolean>) | undefined): AsyncEnumerable<TElement> {
return this.#enumerable.remove(obj, all, equater);
}
concat(...iterables: MaybeAsyncIterable<TElement>[]): AsyncEnumerable<TElement> {
return this.#enumerable.concat(...iterables);
}
first(predicate?: ((obj: TElement) => MaybePromise<boolean>) | undefined): Promise<TElement> {
return this.#enumerable.first(predicate);
}
firstOrDefault(predicate?: ((obj: TElement) => MaybePromise<boolean>) | undefined, def?: TElement | undefined): Promise<TElement | undefined> {
return this.#enumerable.firstOrDefault(predicate, def);
}
last(predicate?: ((obj: TElement) => MaybePromise<boolean>) | undefined): Promise<TElement> {
return this.#enumerable.last(predicate);
}
lastOrDefault(predicate?: ((obj: TElement) => MaybePromise<boolean>) | undefined, def?: TElement | undefined): Promise<TElement | undefined> {
return this.#enumerable.lastOrDefault(predicate, def);
}
single(predicate?: ((obj: TElement) => MaybePromise<boolean>) | undefined): Promise<TElement> {
return this.#enumerable.single(predicate);
}
singleOrDefault(predicate?: ((obj: TElement) => MaybePromise<boolean>) | undefined, def?: TElement | undefined): Promise<TElement | undefined> {
return this.#enumerable.singleOrDefault(predicate, def);
}
elementAt(index: number): Promise<TElement> {
return this.#enumerable.elementAt(index);
}
elementAtOrDefault(index: number, def?: TElement | undefined): Promise<TElement | undefined> {
return this.#enumerable.elementAtOrDefault(index, def);
}
aggregate(accumulator: (acc: TElement, obj: TElement) => MaybePromise<TElement>): Promise<TElement>;
aggregate<TAccumulator>(accumulator: (acc: TAccumulator, obj: TElement) => MaybePromise<TAccumulator>, seed?: TAccumulator | undefined): Promise<TAccumulator>;
aggregate<TAccumulator, TResult>(accumulator: (acc: TAccumulator, obj: TElement) => MaybePromise<TAccumulator>, seed?: TAccumulator | undefined, resultSelector?: ((obj: TAccumulator) => MaybePromise<TResult>) | undefined): Promise<TResult>;
aggregate(accumulator: any, seed?: any, resultSelector?: any) {
return this.#enumerable.aggregate(accumulator, seed, resultSelector);
}
min(): Promise<TElement> {
return this.#enumerable.min();
}
minBy<TBy>(selector: (obj: TElement) => MaybePromise<TBy>): Promise<TElement> {
return this.#enumerable.minBy(selector);
}
max(): Promise<TElement> {
return this.#enumerable.max();
}
maxBy<TBy>(selector: (obj: TElement) => MaybePromise<TBy>): Promise<TElement> {
return this.#enumerable.maxBy(selector);
}
order(comparer?: ((first: TElement, second: TElement) => MaybePromise<number>) | undefined): AsyncEnumerable<TElement> {
return this.#enumerable.order(comparer);
}
orderBy<TBy>(selector: (obj: TElement) => MaybePromise<TBy>, comparer?: ((first: TBy, second: TBy) => MaybePromise<number>) | undefined): AsyncEnumerable<TElement> {
return this.#enumerable.orderBy(selector, comparer);
}
orderDescending(comparer?: ((first: TElement, second: TElement) => MaybePromise<number>) | undefined): AsyncEnumerable<TElement> {
return this.#enumerable.orderDescending(comparer);
}
orderByDescending<TBy>(selector: (obj: TElement) => MaybePromise<TBy>, comparer?: ((first: TBy, second: TBy) => MaybePromise<number>) | undefined): AsyncEnumerable<TElement> {
return this.#enumerable.orderByDescending(selector, comparer);
}
distinct(equater?: ((first: TElement, second: TElement) => MaybePromise<boolean>) | undefined): AsyncEnumerable<TElement> {
return this.#enumerable.distinct(equater);
}
distinctBy<TBy>(selector: (obj: TElement) => MaybePromise<TBy>, equater?: ((first: TBy, second: TBy) => MaybePromise<boolean>) | undefined): AsyncEnumerable<TElement> {
return this.#enumerable.distinctBy(selector, equater);
}
union(iterable: MaybeAsyncIterable<TElement>, equater?: ((first: TElement, second: TElement) => MaybePromise<boolean>) | undefined): AsyncEnumerable<TElement> {
return this.#enumerable.union(iterable, equater);
}
unionBy<TBy>(iterable: MaybeAsyncIterable<TElement>, selector: (obj: TElement) => MaybePromise<TBy>, equater?: ((first: TBy, second: TBy) => MaybePromise<boolean>) | undefined): AsyncEnumerable<TElement> {
return this.#enumerable.unionBy(iterable, selector, equater);
}
except(iterable: MaybeAsyncIterable<TElement>, equater?: ((first: TElement, second: TElement) => MaybePromise<boolean>) | undefined): AsyncEnumerable<TElement> {
return this.#enumerable.except(iterable, equater);
}
exceptBy<TBy>(iterable: MaybeAsyncIterable<TElement>, selector: (obj: TElement) => MaybePromise<TBy>, equater?: ((first: TBy, second: TBy) => MaybePromise<boolean>) | undefined): AsyncEnumerable<TElement> {
return this.#enumerable.exceptBy(iterable, selector, equater);
}
intersect(iterable: MaybeAsyncIterable<TElement>, equater?: ((first: TElement, second: TElement) => MaybePromise<boolean>) | undefined): AsyncEnumerable<TElement> {
return this.#enumerable.intersect(iterable, equater);
}
intersectBy<TBy>(iterable: MaybeAsyncIterable<TElement>, selector: (obj: TElement) => MaybePromise<TBy>, equater?: ((first: TBy, second: TBy) => MaybePromise<boolean>) | undefined): AsyncEnumerable<TElement> {
return this.#enumerable.intersectBy(iterable, selector, equater);
}
all(predicate: (obj: TElement) => MaybePromise<boolean>): Promise<boolean> {
return this.#enumerable.all(predicate);
}
any(predicate: (obj: TElement) => MaybePromise<boolean>): Promise<boolean>;
any(): Promise<boolean>;
any(predicate?: any) {
return this.#enumerable.any(predicate);
}
none(predicate: Predicate<TElement>): Promise<boolean>;
none(): Promise<boolean>;
none(predicate?: any) {
return this.#enumerable.none(predicate);
}
skip(n: number): AsyncEnumerable<TElement> {
return this.#enumerable.skip(n);
}
skipLast(n: number): AsyncEnumerable<TElement> {
return this.#enumerable.skipLast(n);
}
skipWhile(condition: (obj: TElement) => MaybePromise<boolean>): AsyncEnumerable<TElement> {
return this.#enumerable.skipWhile(condition);
}
take(n: number): AsyncEnumerable<TElement> {
return this.#enumerable.take(n);
}
takeLast(n: number): AsyncEnumerable<TElement> {
return this.#enumerable.takeLast(n);
}
takeWhile(condition: (obj: TElement) => MaybePromise<boolean>): AsyncEnumerable<TElement> {
return this.#enumerable.takeWhile(condition);
}
peek(action: (obj: TElement) => MaybePromise<void>): AsyncEnumerable<TElement> {
return this.#enumerable.peek(action);
}
forEach(action: (obj: TElement) => MaybePromise<void>): Promise<void> {
return this.#enumerable.forEach(action);
}
zip<TOther>(iterable: MaybeAsyncIterable<TOther>): AsyncEnumerable<[TElement, TOther]> {
return this.#enumerable.zip(iterable);
}
indexex(): AsyncEnumerable<[number, TElement]> {
return this.#enumerable.indexex();
}
reversed(): AsyncEnumerable<TElement> {
return this.#enumerable.reversed();
}
chunked(size: number): AsyncEnumerable<TElement[]> {
return this.#enumerable.chunked(size);
}
cached(): AsyncEnumerable<TElement> {
return this.#enumerable.cached();
}
asArray(): Promise<TElement[]> {
return this.#enumerable.asArray();
}
toArray(): Promise<TElement[]> {
return this.#enumerable.toArray();
}
toMap<TKey, TValue>(keySelector: (obj: TElement) => MaybePromise<TKey>, valueSelector: (obj: TElement) => MaybePromise<TValue>): Promise<Map<TKey, TValue>> {
return this.#enumerable.toMap(keySelector, valueSelector);
}
toSet(): Promise<Set<TElement>> {
return this.#enumerable.toSet();
}
toObject<TValue>(keySelector: (obj: TElement) => MaybePromise<PropertyKey>, valueSelector: (obj: TElement) => MaybePromise<TValue>): Promise<Record<PropertyKey, TValue>> {
return this.#enumerable.toObject(keySelector, valueSelector);
}
collect<TResult>(collector: Collector<TElement, any, TResult>): Promise<TResult> {
return this.#enumerable.collect(collector);
}
}
class GroupedAsyncEnumerableImpl<TElement, TKey> extends DelegatedAsyncEnumerable<TElement> implements GroupedAsyncEnumerable<TKey, TElement> {
readonly #key: TKey;
constructor(key: TKey, grouping: AsyncEnumerable<TElement>) {
super(grouping);
this.#key = key;
this.#grouping = grouping;
}
public get key() {
return this.#key;
}
override async nonEnumeratedCount() {
return await this.#grouping.nonEnumeratedCount();
}
override iterator() {
return this.#grouping.iterator();
}
}
abstract class BaseOrderedAsyncEnumerable<TElement> extends BaseAsyncEnumerable<TElement> implements OrderedAsyncEnumerable<TElement> {
@@ -954,6 +1262,10 @@ abstract class BaseOrderedAsyncEnumerable<TElement> extends BaseAsyncEnumerable<
return await this.#enumerable.nonEnumeratedCount();
}
override async maxCount() {
return await this.#enumerable.maxCount();
}
get comparer() {
return this.#sorter;
}
@@ -1922,7 +2234,7 @@ class GroupByAsyncEnumerable<TElement, TKey, TResult> extends BaseAsyncEnumerabl
}
for await (const entry of groupings) {
yield new GroupedAsyncEnumerableImpl(entry[0], array(entry[1]));
yield new GroupedAsyncEnumerableImpl(entry[0], AsyncEnumerable.array(entry[1]));
}
}
}
@@ -2032,7 +2344,7 @@ class GroupJoinAsyncEnumerable<TOuter, TInner, TKey, TResult> extends BaseAsyncE
}
// yield this.#resultSelector(firstObj, this.#second.where(secondObj => this.#keyComparer(firstKey, this.#secondKeySelector(secondObj))));
yield this.#resultSelector(firstObj, array(secondObjs));
yield this.#resultSelector(firstObj, AsyncEnumerable.array(secondObjs));
}
}
}

View File

@@ -1,5 +1,5 @@
import { join } from "./collector.js";
import { arrayLike, sequence } from "./sync.js";
import { Enumerable } from "./sync.js";
import { asArray, isDefined } from "./utils.js";
export interface BitArray extends Iterable<boolean> {
@@ -224,16 +224,16 @@ class BitArrayImpl implements BitArray {
this.#ensureSameSize(other);
return other instanceof BitArrayImpl ?
arrayLike(this.#bits).zip(arrayLike(other.#bits)).all(([a, b]) => (a & b) === b) :
sequence(this).zip(sequence(other)).where(([, b]) => b).all(([a, b]) => a && b);
Enumerable.arrayLike(this.#bits).zip(Enumerable.arrayLike(other.#bits)).all(([a, b]) => (a & b) === b) :
Enumerable.sequence(this).zip(Enumerable.sequence(other)).where(([, b]) => b).all(([a, b]) => a && b);
}
public intersects(other: BitArray) {
this.#ensureSameSize(other);
return other instanceof BitArrayImpl ?
arrayLike(this.#bits).zip(arrayLike(other.#bits)).any(([a, b]) => (a & b) !== 0) :
sequence(this).zip(sequence(other)).any(([a, b]) => a && b);
Enumerable.arrayLike(this.#bits).zip(Enumerable.arrayLike(other.#bits)).any(([a, b]) => (a & b) !== 0) :
Enumerable.sequence(this).zip(Enumerable.sequence(other)).any(([a, b]) => a && b);
}
public slice(offset: number, length: number) {
@@ -247,15 +247,15 @@ class BitArrayImpl implements BitArray {
}
public toArray() {
return sequence(this).toArray();
return Enumerable.sequence(this).toArray();
}
public equals(other: BitArray) {
return other === this || isDefined(other) && (other instanceof BitArrayImpl ? arrayLike(this.#bits).equals(arrayLike(other.#bits)) : sequence(this).equals(sequence(other)));
return other === this || isDefined(other) && (other instanceof BitArrayImpl ? Enumerable.arrayLike(this.#bits).sequenceEquals(Enumerable.arrayLike(other.#bits)) : Enumerable.sequence(this).sequenceEquals(Enumerable.sequence(other)));
}
public toString() {
return sequence(this).select(bit => bit ? '1' : '0').collect(join());
return Enumerable.sequence(this).select(bit => bit ? '1' : '0').collect(join());
}
}
@@ -465,13 +465,13 @@ class BitArraySlice implements BitArray {
public contains(other: BitArray) {
this.#ensureSameSize(other);
return sequence(this).zip(sequence(other)).where(([, b]) => b).all(([a, b]) => a && b);
return Enumerable.sequence(this).zip(Enumerable.sequence(other)).where(([, b]) => b).all(([a, b]) => a && b);
}
public intersects(other: BitArray) {
this.#ensureSameSize(other);
return sequence(this).zip(sequence(other)).any(([a, b]) => a && b);
return Enumerable.sequence(this).zip(Enumerable.sequence(other)).any(([a, b]) => a && b);
}
public slice(offset: number, length: number) {
@@ -489,15 +489,15 @@ class BitArraySlice implements BitArray {
}
public toArray() {
return sequence(this).toArray();
return Enumerable.sequence(this).toArray();
}
public equals(other: BitArray) {
return other === this || isDefined(other) && sequence(this).equals(sequence(other));
return other === this || isDefined(other) && Enumerable.sequence(this).sequenceEquals(Enumerable.sequence(other));
}
public toString() {
return sequence(this).select(bit => bit ? '1' : '0').collect(join());
return Enumerable.sequence(this).select(bit => bit ? '1' : '0').collect(join());
}
}

View File

@@ -1,4 +1,4 @@
export * from "./sync.js";
export * as async from "./async.js";
export * from "./async.js";
export * as collectors from "./collector.js";
export * as random from "./random.js";

View File

@@ -41,7 +41,7 @@ export interface Enumerable<TElement> extends Iterable<TElement> {
contains(obj: TElement, equater?: Equater<TElement>): boolean;
equals(iterable: Iterable<TElement>, equater?: Equater<TElement>): boolean;
sequenceEquals(iterable: Iterable<TElement>, equater?: Equater<TElement>): boolean;
append(obj: TElement): Enumerable<TElement>;
@@ -146,6 +146,7 @@ export interface OrderedEnumerable<TElement> extends Enumerable<TElement> {
thenByDescending<TBy>(selector: Converter<TElement, TBy>, comparer?: Comparer<TBy>): OrderedEnumerable<TElement>;
}
export namespace Enumerable {
export function wrap<T>(iterable: Iterable<T>): Enumerable<T> {
if (isEnumerable<T>(iterable)) {
return iterable;
@@ -288,6 +289,7 @@ export function concat<T>(...enumerables: Enumerable<T>[]): Enumerable<T> {
export function isEnumerable<T = any>(obj: any): obj is Enumerable<T> {
return obj instanceof EnumerableMarker;
}
}
//#region enumerable implementation
@@ -323,11 +325,11 @@ export abstract class BaseEnumerable<TElement> extends EnumerableMarker implemen
}
join<TOther, TKey, TResult>(iterable: Iterable<TOther>, firstKeySelector: Converter<TElement, TKey>, secondKeySelector: Converter<TOther, TKey>, resultSelector?: BiConverter<TElement, TOther, TResult>, keyComparer?: Equater<TKey>): Enumerable<TResult> {
return new JoinEnumerable<TElement, TOther, TKey, TResult>(this, wrap(iterable), firstKeySelector, secondKeySelector, resultSelector, keyComparer);
return new JoinEnumerable<TElement, TOther, TKey, TResult>(this, Enumerable.wrap(iterable), firstKeySelector, secondKeySelector, resultSelector, keyComparer);
}
groupJoin<TOther, TKey, TResult>(iterable: Iterable<TOther>, firstKeySelector: Converter<TElement, TKey>, secondKeySelector: Converter<TOther, TKey>, resultSelector?: BiConverter<TElement, Enumerable<TOther>, TResult>, keyComparer?: Equater<TKey>): Enumerable<TResult> {
return new GroupJoinEnumerable<TElement, TOther, TKey, TResult>(this, wrap(iterable), firstKeySelector, secondKeySelector, resultSelector, keyComparer);
return new GroupJoinEnumerable<TElement, TOther, TKey, TResult>(this, Enumerable.wrap(iterable), firstKeySelector, secondKeySelector, resultSelector, keyComparer);
}
contains(obj: TElement, equater?: Equater<TElement>) {
@@ -344,8 +346,12 @@ export abstract class BaseEnumerable<TElement> extends EnumerableMarker implemen
return false;
}
equals(iterable: Iterable<TElement>, equater?: Equater<TElement>) {
const that = wrap(iterable);
sequenceEquals(iterable: Iterable<TElement>, equater?: Equater<TElement>) {
if (this === iterable) {
return true;
}
const that = Enumerable.wrap(iterable);
const thisCount = this.nonEnumeratedCount();
const thatCount = that.nonEnumeratedCount();
@@ -399,7 +405,7 @@ export abstract class BaseEnumerable<TElement> extends EnumerableMarker implemen
const arr: Enumerable<TElement>[] = [this];
for (const iterable of iterables) {
arr.push(wrap(iterable));
arr.push(Enumerable.wrap(iterable));
}
return new ConcatEnumerable(arr);
@@ -743,27 +749,27 @@ export abstract class BaseEnumerable<TElement> extends EnumerableMarker implemen
}
union(iterable: Iterable<TElement>, equater?: Equater<TElement>): Enumerable<TElement> {
return new UnionEnumerable<TElement>(this, wrap(iterable), equater);
return new UnionEnumerable<TElement>(this, Enumerable.wrap(iterable), equater);
}
unionBy<TBy>(iterable: Iterable<TElement>, selector: Converter<TElement, TBy>, equater?: Equater<TBy>): Enumerable<TElement> {
return new UnionByEnumerable<TElement, TBy>(this, wrap(iterable), selector, equater);
return new UnionByEnumerable<TElement, TBy>(this, Enumerable.wrap(iterable), selector, equater);
}
except(iterable: Iterable<TElement>): Enumerable<TElement> {
return new ExceptEnumerable<TElement>(this, wrap(iterable));
return new ExceptEnumerable<TElement>(this, Enumerable.wrap(iterable));
}
exceptBy<TBy>(iterable: Iterable<TElement>, selector: Converter<TElement, TBy>): Enumerable<TElement> {
return new ExceptByEnumerable<TElement, TBy>(this, wrap(iterable), selector);
return new ExceptByEnumerable<TElement, TBy>(this, Enumerable.wrap(iterable), selector);
}
intersect(iterable: Iterable<TElement>): Enumerable<TElement> {
return new IntersectEnumerable<TElement>(this, wrap(iterable));
return new IntersectEnumerable<TElement>(this, Enumerable.wrap(iterable));
}
intersectBy<TBy>(iterable: Iterable<TElement>, selector: Converter<TElement, TBy>): Enumerable<TElement> {
return new IntersectByEnumerable<TElement, TBy>(this, wrap(iterable), selector);
return new IntersectByEnumerable<TElement, TBy>(this, Enumerable.wrap(iterable), selector);
}
all(predicate: Predicate<TElement>) {
@@ -847,7 +853,7 @@ export abstract class BaseEnumerable<TElement> extends EnumerableMarker implemen
throw new Error("Cannot take a negative number of elements.");
}
return n === 0 ? empty<TElement>() : new TakeEnumerable<TElement>(this, n);
return n === 0 ? Enumerable.empty<TElement>() : new TakeEnumerable<TElement>(this, n);
}
takeLast(n: number): Enumerable<TElement> {
@@ -855,7 +861,7 @@ export abstract class BaseEnumerable<TElement> extends EnumerableMarker implemen
throw new Error("Cannot take a negative number of elements.");
}
return n === 0 ? empty<TElement>() : new TakeLastEnumerable<TElement>(this, n);
return n === 0 ? Enumerable.empty<TElement>() : new TakeLastEnumerable<TElement>(this, n);
}
takeWhile(predicate: Predicate<TElement>): Enumerable<TElement> {
@@ -873,7 +879,7 @@ export abstract class BaseEnumerable<TElement> extends EnumerableMarker implemen
}
zip<TOther>(iterable: Iterable<TOther>): Enumerable<[TElement, TOther]> {
return new ZippedEnumerable<TElement, TOther>(this, wrap(iterable));
return new ZippedEnumerable<TElement, TOther>(this, Enumerable.wrap(iterable));
}
indexed(): Enumerable<[number, TElement]> {
@@ -1025,8 +1031,8 @@ class DelegatedEnumerable<TElement> extends EnumerableMarker implements Enumerab
return this.#enumerable.contains(obj, equater);
}
equals(iterable: Iterable<TElement>, equater?: Equater<TElement>) {
return this.#enumerable.equals(iterable, equater);
sequenceEquals(iterable: Iterable<TElement>, equater?: Equater<TElement>) {
return this.#enumerable.sequenceEquals(iterable, equater);
}
append(obj: TElement) {
@@ -2495,7 +2501,7 @@ class GroupByEnumerable<TElement, TKey, TResult> extends BaseEnumerable<GroupedE
}
for (const entry of groupings) {
yield new GroupedEnumerableImpl(entry[0], array(entry[1]));
yield new GroupedEnumerableImpl(entry[0], Enumerable.array(entry[1]));
}
}
}
@@ -2624,7 +2630,7 @@ class GroupJoinEnumerable<TOuter, TInner, TKey, TResult> extends BaseEnumerable<
}
}
yield this.#resultSelector(firstObj, array(secondObjs));
yield this.#resultSelector(firstObj, Enumerable.array(secondObjs));
}
}
}
@@ -2677,7 +2683,7 @@ class CacheEnumerable<T> extends DelegatedEnumerable<T> {
override iterator() {
if (!this.#cached) {
this.enumerable = array(this.enumerable.toArray());
this.enumerable = Enumerable.array(this.enumerable.toArray());
this.#cached = true;
}