1
0

Compare commits

...

7 Commits

6 changed files with 350 additions and 94 deletions

View File

@@ -456,6 +456,14 @@ export abstract class BaseAsyncSequence<TElement> extends AsyncSequenceMarker im
return new OrderByAsyncSequence<TElement, TBy>(this, true, selector, comparer);
}
partition(equater?: MaybeAsyncEquater<TElement>): AsyncSequence<Awaited<TElement>[]> {
return new PartitionAsyncSequence<TElement>(this, equater);
}
partitionBy<TBy>(selector: MaybeAsyncConverter<TElement, TBy>, equater?: MaybeAsyncEquater<TBy>): AsyncSequence<Awaited<TElement>[]> {
return new PartitionByAsyncSequence<TElement, TBy>(this, selector, equater);
}
distinct(equater?: MaybeAsyncEquater<TElement>): AsyncSequence<TElement> {
return new DistinctAsyncSequence<TElement>(this, equater);
}
@@ -849,6 +857,14 @@ export class DelegatedAsyncSequence<TElement> extends AsyncSequenceMarker implem
return this.#sequence.orderByDescending(selector, comparer);
}
partition(equater?: MaybeAsyncEquater<TElement> | undefined): AsyncSequence<Awaited<TElement>[]> {
return this.#sequence.partition(equater);
}
partitionBy<TBy>(selector: MaybeAsyncConverter<TElement, TBy>, equater?: MaybeAsyncEquater<TBy> | undefined): AsyncSequence<Awaited<TElement>[]> {
return this.#sequence.partitionBy(selector, equater);
}
distinct(equater?: ((first: TElement, second: TElement) => MaybePromise<boolean>) | undefined): AsyncSequence<TElement> {
return this.#sequence.distinct(equater);
}
@@ -1284,7 +1300,7 @@ export class ConcatAsyncSequence<T> extends BaseAsyncSequence<T> {
}
}
export class DistinctAsyncSequence<T> extends BaseAsyncSequence<T> {
class DistinctAsyncSequence<T> extends BaseAsyncSequence<T> {
readonly #sequence: AsyncSequence<T>;
readonly #equater: MaybeAsyncEquater<T> | undefined;
@@ -1306,7 +1322,7 @@ export class DistinctAsyncSequence<T> extends BaseAsyncSequence<T> {
}
}
export class DistinctByAsyncSequence<T, U> extends BaseAsyncSequence<T> {
class DistinctByAsyncSequence<T, U> extends BaseAsyncSequence<T> {
readonly #sequence: AsyncSequence<T>;
readonly #selector: MaybeAsyncConverter<T, U>;
readonly #equater: MaybeAsyncEquater<U> | undefined;
@@ -1328,11 +1344,11 @@ export class DistinctByAsyncSequence<T, U> extends BaseAsyncSequence<T> {
}
}
await set.clear();
set.clear();
}
}
export class FilterAsyncSequence<T> extends BaseAsyncSequence<T> {
class FilterAsyncSequence<T> extends BaseAsyncSequence<T> {
readonly #sequence: AsyncSequence<T>;
readonly #predicate: MaybeAsyncPredicate<T>;
@@ -1352,7 +1368,7 @@ export class FilterAsyncSequence<T> extends BaseAsyncSequence<T> {
}
}
export class FlatMapperAsyncSequence<T, U> extends BaseAsyncSequence<U> {
class FlatMapperAsyncSequence<T, U> extends BaseAsyncSequence<U> {
readonly #sequence: AsyncSequence<T>;
readonly #converter: MaybeAsyncConverter<T, MaybeAsyncIterable<U>>;
@@ -1370,7 +1386,7 @@ export class FlatMapperAsyncSequence<T, U> extends BaseAsyncSequence<U> {
}
}
export class IndexedAsyncSequence<T> extends BaseAsyncSequence<[number, Awaited<T>]> {
class IndexedAsyncSequence<T> extends BaseAsyncSequence<[number, Awaited<T>]> {
readonly #sequence: AsyncSequence<T>;
constructor(sequence: AsyncSequence<T>) {
@@ -1388,7 +1404,7 @@ export class IndexedAsyncSequence<T> extends BaseAsyncSequence<[number, Awaited<
}
}
export class MapperAsyncSequence<T, U> extends BaseAsyncSequence<U> {
class MapperAsyncSequence<T, U> extends BaseAsyncSequence<U> {
readonly #sequence: AsyncSequence<T>;
readonly #converter: MaybeAsyncConverter<T, U>;
@@ -1410,7 +1426,7 @@ export class MapperAsyncSequence<T, U> extends BaseAsyncSequence<U> {
}
}
export class SkipWhileAsyncSequence<T> extends BaseAsyncSequence<T> {
class SkipWhileAsyncSequence<T> extends BaseAsyncSequence<T> {
readonly #sequence: AsyncSequence<T>;
readonly #predicate: MaybeAsyncPredicate<T>;
@@ -1443,7 +1459,7 @@ export class SkipWhileAsyncSequence<T> extends BaseAsyncSequence<T> {
}
}
export class SkipLastAsyncSequence<T> extends BaseAsyncSequence<T> {
class SkipLastAsyncSequence<T> extends BaseAsyncSequence<T> {
readonly #sequence: AsyncSequence<T>;
readonly #n: number;
@@ -1484,7 +1500,7 @@ export class SkipLastAsyncSequence<T> extends BaseAsyncSequence<T> {
}
}
export class SkipAsyncSequence<T> extends BaseAsyncSequence<T> {
class SkipAsyncSequence<T> extends BaseAsyncSequence<T> {
readonly #sequence: AsyncSequence<T>;
readonly #n: number;
@@ -1516,7 +1532,7 @@ export class SkipAsyncSequence<T> extends BaseAsyncSequence<T> {
}
}
export class TakeWhileAsyncSequence<T> extends BaseAsyncSequence<T> {
class TakeWhileAsyncSequence<T> extends BaseAsyncSequence<T> {
readonly #sequence: AsyncSequence<T>;
readonly #predicate: MaybeAsyncPredicate<T>;
@@ -1538,7 +1554,7 @@ export class TakeWhileAsyncSequence<T> extends BaseAsyncSequence<T> {
}
}
export class TakeLastAsyncSequence<T> extends BaseAsyncSequence<T> {
class TakeLastAsyncSequence<T> extends BaseAsyncSequence<T> {
readonly #sequence: AsyncSequence<T>;
readonly #n: number;
@@ -1565,7 +1581,7 @@ export class TakeLastAsyncSequence<T> extends BaseAsyncSequence<T> {
}
}
export class TakeAsyncSequence<T> extends BaseAsyncSequence<T> {
class TakeAsyncSequence<T> extends BaseAsyncSequence<T> {
readonly #sequence: AsyncSequence<T>;
readonly #n: number;
@@ -1598,13 +1614,13 @@ export class TakeAsyncSequence<T> extends BaseAsyncSequence<T> {
}
}
export class OrderAsyncSequence<T> extends BaseOrderedAsyncSequence<T> {
class OrderAsyncSequence<T> extends BaseOrderedAsyncSequence<T> {
constructor(sequence: AsyncSequence<T>, descending: boolean, sorter?: MaybeAsyncComparer<T>) {
super(sequence, sorter ?? defaultArrayComparer, descending);
}
}
export class OrderByAsyncSequence<T, U> extends BaseOrderedAsyncSequence<T> {
class OrderByAsyncSequence<T, U> extends BaseOrderedAsyncSequence<T> {
constructor(sequence: AsyncSequence<T>, descending: boolean, selector: MaybeAsyncConverter<T, U>, sorter?: MaybeAsyncComparer<U>) {
super(sequence, OrderByAsyncSequence.#createSorter(selector, sorter), descending);
}
@@ -1615,13 +1631,13 @@ export class OrderByAsyncSequence<T, U> extends BaseOrderedAsyncSequence<T> {
}
}
export class ThenOrderAsyncSequence<T> extends BaseOrderedAsyncSequence<T> {
class ThenOrderAsyncSequence<T> extends BaseOrderedAsyncSequence<T> {
constructor(sequence: OrderedAsyncSequence<T>, descending: boolean, sorter?: MaybeAsyncComparer<T>) {
super(sequence, combineAsyncComparers(sequence.comparer ?? defaultArrayComparer, sorter ?? defaultArrayComparer), descending);
}
}
export class ThenOrderByAsyncSequence<T, U> extends BaseOrderedAsyncSequence<T> {
class ThenOrderByAsyncSequence<T, U> extends BaseOrderedAsyncSequence<T> {
constructor(sequence: OrderedAsyncSequence<T>, descending: boolean, selector: MaybeAsyncConverter<T, U>, sorter?: MaybeAsyncComparer<U>) {
super(sequence, ThenOrderByAsyncSequence.#createCombinedSorter(sequence.comparer, selector, sorter), descending);
}
@@ -1633,7 +1649,7 @@ export class ThenOrderByAsyncSequence<T, U> extends BaseOrderedAsyncSequence<T>
}
}
export class AppendAsyncSequence<T> extends BaseAsyncSequence<T> {
class AppendAsyncSequence<T> extends BaseAsyncSequence<T> {
readonly #sequence: AsyncSequence<T>;
readonly #obj: T;
@@ -1655,7 +1671,7 @@ export class AppendAsyncSequence<T> extends BaseAsyncSequence<T> {
}
}
export class PrependAsyncSequence<T> extends BaseAsyncSequence<T> {
class PrependAsyncSequence<T> extends BaseAsyncSequence<T> {
readonly #sequence: AsyncSequence<T>;
readonly #obj: T;
@@ -1677,7 +1693,7 @@ export class PrependAsyncSequence<T> extends BaseAsyncSequence<T> {
}
}
export class PeekAsyncSequence<T> extends BaseAsyncSequence<T> {
class PeekAsyncSequence<T> extends BaseAsyncSequence<T> {
readonly #sequence: AsyncSequence<T>;
readonly #action: MaybeAsyncAction<T>;
@@ -1700,7 +1716,7 @@ export class PeekAsyncSequence<T> extends BaseAsyncSequence<T> {
}
}
export class ZippedAsyncSequence<T, U> extends BaseAsyncSequence<[Awaited<T>, Awaited<U>]> {
class ZippedAsyncSequence<T, U> extends BaseAsyncSequence<[Awaited<T>, Awaited<U>]> {
readonly #first: AsyncSequence<T>;
readonly #second: AsyncSequence<U>;
@@ -1735,7 +1751,7 @@ export class ZippedAsyncSequence<T, U> extends BaseAsyncSequence<[Awaited<T>, Aw
}
}
export class UnionAsyncSequence<T> extends BaseAsyncSequence<T> {
class UnionAsyncSequence<T> extends BaseAsyncSequence<T> {
readonly #first: AsyncSequence<T>;
readonly #second: AsyncSequence<T>;
readonly #equater: MaybeAsyncEquater<T> | undefined;
@@ -1763,11 +1779,11 @@ export class UnionAsyncSequence<T> extends BaseAsyncSequence<T> {
}
}
await set.clear();
set.clear();
}
}
export class UnionByAsyncSequence<T, U> extends BaseAsyncSequence<T> {
class UnionByAsyncSequence<T, U> extends BaseAsyncSequence<T> {
readonly #first: AsyncSequence<T>;
readonly #second: AsyncSequence<T>;
readonly #selector: MaybeAsyncConverter<T, U>;
@@ -1797,11 +1813,11 @@ export class UnionByAsyncSequence<T, U> extends BaseAsyncSequence<T> {
}
}
await set.clear();
set.clear();
}
}
export class ExceptAsyncSequence<T> extends BaseAsyncSequence<T> {
class ExceptAsyncSequence<T> extends BaseAsyncSequence<T> {
readonly #first: AsyncSequence<T>;
readonly #second: AsyncSequence<T>;
readonly #equater: MaybeAsyncEquater<T> | undefined;
@@ -1827,11 +1843,11 @@ export class ExceptAsyncSequence<T> extends BaseAsyncSequence<T> {
}
}
await set.clear();
set.clear();
}
}
export class ExceptByAsyncSequence<T, U> extends BaseAsyncSequence<T> {
class ExceptByAsyncSequence<T, U> extends BaseAsyncSequence<T> {
readonly #first: AsyncSequence<T>;
readonly #second: AsyncSequence<T>;
readonly #selector: MaybeAsyncConverter<T, U>;
@@ -1859,11 +1875,11 @@ export class ExceptByAsyncSequence<T, U> extends BaseAsyncSequence<T> {
}
}
await set.clear();
set.clear();
}
}
export class IntersectAsyncSequence<T> extends BaseAsyncSequence<T> {
class IntersectAsyncSequence<T> extends BaseAsyncSequence<T> {
readonly #first: AsyncSequence<T>;
readonly #second: AsyncSequence<T>;
readonly #equater: MaybeAsyncEquater<T> | undefined;
@@ -1889,11 +1905,11 @@ export class IntersectAsyncSequence<T> extends BaseAsyncSequence<T> {
}
}
await set.clear();
set.clear();
}
}
export class IntersectByAsyncSequence<T, U> extends BaseAsyncSequence<T> {
class IntersectByAsyncSequence<T, U> extends BaseAsyncSequence<T> {
readonly #first: AsyncSequence<T>;
readonly #second: AsyncSequence<T>;
readonly #selector: MaybeAsyncConverter<T, U>;
@@ -1921,11 +1937,11 @@ export class IntersectByAsyncSequence<T, U> extends BaseAsyncSequence<T> {
}
}
await set.clear();
set.clear();
}
}
export class ReversedAsyncSequence<T> extends BaseAsyncSequence<T> {
class ReversedAsyncSequence<T> extends BaseAsyncSequence<T> {
readonly #sequence: AsyncSequence<T>;
constructor(sequence: AsyncSequence<T>) {
@@ -1947,7 +1963,7 @@ export class ReversedAsyncSequence<T> extends BaseAsyncSequence<T> {
}
}
export class GroupByAsyncSequence<TElement, TKey, TResult> extends BaseAsyncSequence<GroupedAsyncSequence<TKey, TResult>> {
class GroupByAsyncSequence<TElement, TKey, TResult> extends BaseAsyncSequence<GroupedAsyncSequence<TKey, TResult>> {
readonly #sequence: AsyncSequence<TElement>;
readonly #keySelector: MaybeAsyncConverter<TElement, TKey>;
readonly #elementSelector: MaybeAsyncConverter<TElement, TResult>;
@@ -1976,13 +1992,13 @@ export class GroupByAsyncSequence<TElement, TKey, TResult> extends BaseAsyncSequ
grouping.push(await this.#elementSelector(obj));
}
for await (const entry of groupings) {
for (const entry of groupings) {
yield new GroupedAsyncSequenceImpl(entry[0], array(entry[1]));
}
}
}
export class ChunkedAsyncSequence<T> extends BaseAsyncSequence<T[]> {
class ChunkedAsyncSequence<T> extends BaseAsyncSequence<T[]> {
readonly #sequence: AsyncSequence<T>;
readonly #size: number;
@@ -2016,7 +2032,7 @@ export class ChunkedAsyncSequence<T> extends BaseAsyncSequence<T[]> {
}
}
export class JoinAsyncSequence<TOuter, TInner, TKey, TResult> extends BaseAsyncSequence<TResult> {
class JoinAsyncSequence<TOuter, TInner, TKey, TResult> extends BaseAsyncSequence<TResult> {
readonly #first: AsyncSequence<TOuter>;
readonly #second: AsyncSequence<TInner>;
readonly #firstKeySelector: MaybeAsyncConverter<TOuter, TKey>;
@@ -2050,7 +2066,7 @@ export class JoinAsyncSequence<TOuter, TInner, TKey, TResult> extends BaseAsyncS
}
}
export class GroupJoinAsyncSequence<TOuter, TInner, TKey, TResult> extends BaseAsyncSequence<TResult> {
class GroupJoinAsyncSequence<TOuter, TInner, TKey, TResult> extends BaseAsyncSequence<TResult> {
readonly #first: AsyncSequence<TOuter>;
readonly #second: AsyncSequence<TInner>;
readonly #firstKeySelector: MaybeAsyncConverter<TOuter, TKey>;
@@ -2092,7 +2108,7 @@ export class GroupJoinAsyncSequence<TOuter, TInner, TKey, TResult> extends BaseA
}
}
export class RemoveAsyncSequence<T> extends BaseAsyncSequence<T> {
class RemoveAsyncSequence<T> extends BaseAsyncSequence<T> {
readonly #sequence: AsyncSequence<T>;
readonly #obj: T;
readonly #all: boolean;
@@ -2127,7 +2143,7 @@ export class RemoveAsyncSequence<T> extends BaseAsyncSequence<T> {
}
}
export class CacheAsyncSequence<T> extends BaseAsyncSequence<T> {
class CacheAsyncSequence<T> extends BaseAsyncSequence<T> {
readonly #sequence: AsyncSequence<T>;
#cache: T[] | undefined;
@@ -2141,3 +2157,62 @@ export class CacheAsyncSequence<T> extends BaseAsyncSequence<T> {
yield* this.#cache ??= await this.#sequence.toArray();
}
}
class PartitionAsyncSequence<T> extends BaseAsyncSequence<Awaited<T>[]> {
readonly #sequence: AsyncSequence<T>;
readonly #equater: MaybeAsyncEquater<T>;
constructor(sequence: AsyncSequence<T>, equater: MaybeAsyncEquater<T> | undefined) {
super();
this.#sequence = sequence;
this.#equater = equater ?? strictEquals;
}
override async *iterator() {
const partitions = createAsyncEqualityMap<T, Awaited<T>[]>(this.#equater);
for await (const obj of this.#sequence) {
const partition = await partitions.get(obj);
if (partition) {
partition.push(obj);
} else {
await partitions.set(obj, [obj]);
}
}
yield* partitions.values();
}
}
class PartitionByAsyncSequence<TElement, TBy> extends BaseAsyncSequence<Awaited<TElement>[]> {
readonly #sequence: AsyncSequence<TElement>;
readonly #selector: MaybeAsyncConverter<TElement, TBy>;
readonly #equater: MaybeAsyncEquater<TBy>;
constructor(sequence: AsyncSequence<TElement>, selector: MaybeAsyncConverter<TElement, TBy>, equater: MaybeAsyncEquater<TBy> | undefined) {
super();
this.#sequence = sequence;
this.#selector = selector;
this.#equater = equater ?? strictEquals;
}
override async *iterator() {
const partitions = createAsyncEqualityMap<TBy, Awaited<TElement>[]>(this.#equater);
for await (const obj of this.#sequence) {
const key = await this.#selector(obj);
const partition = await partitions.get(key);
if (partition) {
partition.push(obj);
} else {
await partitions.set(key, [obj]);
}
}
yield* partitions.values();
}
}

View File

@@ -66,6 +66,9 @@ export interface AsyncSequence<TElement> extends AsyncIterable<Awaited<TElement>
orderDescending(comparer?: MaybeAsyncComparer<TElement>): AsyncSequence<TElement>;
orderByDescending<TBy>(selector: MaybeAsyncConverter<TElement, TBy>, comparer?: MaybeAsyncComparer<TBy>): AsyncSequence<TElement>;
partition(equater?: MaybeAsyncEquater<TElement>): AsyncSequence<Awaited<TElement>[]>;
partitionBy<TBy>(selector: MaybeAsyncConverter<TElement, TBy>, equater?: MaybeAsyncEquater<TBy>): AsyncSequence<Awaited<TElement>[]>;
distinct(equater?: MaybeAsyncEquater<TElement>): AsyncSequence<TElement>;
distinctBy<TBy>(selector: MaybeAsyncConverter<TElement, TBy>, equater?: MaybeAsyncEquater<TBy>): AsyncSequence<TElement>;

View File

@@ -1,17 +1,24 @@
import { Equater, MaybeAsyncEquater } from "./types.js";
import { asAsyncGenerator } from "./utils.js";
export interface EqualityMap<K, V> extends Iterable<[K, V]> {
readonly size: number;
get(key: K): V | undefined;
set(key: K, value: V): V | undefined;
contains(key: K): boolean;
remove(key: K): V | undefined;
clear(): void;
keys(): IterableIterator<K>;
values(): IterableIterator<V>;
entries(): IterableIterator<[K, V]>;
}
class NativeEqualityMap<K, V> implements EqualityMap<K, V> {
readonly #map = new Map<K, V>();
get size() {
return this.#map.size;
}
get(key: K) {
return this.#map.get(key);
}
@@ -36,6 +43,18 @@ class NativeEqualityMap<K, V> implements EqualityMap<K, V> {
this.#map.clear();
}
keys() {
return this.#map.keys();
}
values() {
return this.#map.values();
}
entries() {
return this.#map.entries();
}
[Symbol.iterator]() {
return this.#map[Symbol.iterator]();
}
@@ -49,6 +68,10 @@ class CustomEqualityMap<K, V> implements EqualityMap<K, V> {
this.#keyComparer = keyComparer;
}
get size() {
return this.#list.length;
}
get(key: K) {
for (const entry of this.#list) {
if (this.#keyComparer(key, entry[0])) {
@@ -98,8 +121,26 @@ class CustomEqualityMap<K, V> implements EqualityMap<K, V> {
this.#list.length = 0;
}
[Symbol.iterator]() {
return this.#list[Symbol.iterator]();
*keys() {
for (const entry of this.#list) {
yield entry[0];
}
}
*values() {
for (const entry of this.#list) {
yield entry[1];
}
}
entries() {
return this[Symbol.iterator]();
}
*[Symbol.iterator]() {
for (const entry of this.#list) {
yield [entry[0], entry[1]] as [K, V]; // no entry mutation allowed!
}
}
}
@@ -107,17 +148,25 @@ export function createEqualityMap<K, V>(keyComparer?: Equater<K>): EqualityMap<K
return keyComparer ? new CustomEqualityMap<K, V>(keyComparer) : new NativeEqualityMap<K, V>();
}
export interface AsyncEqualityMap<K, V> extends AsyncIterable<[K, V]> {
export interface AsyncEqualityMap<K, V> extends Iterable<[K, V]> {
readonly size: number;
get(key: K): Promise<V | undefined>;
set(key: K, value: V): Promise<V | undefined>;
contains(key: K): Promise<boolean>;
remove(key: K): Promise<V | undefined>;
clear(): Promise<void>;
clear(): void;
keys(): IterableIterator<K>;
values(): IterableIterator<V>;
entries(): IterableIterator<[K, V]>;
}
class NativeAsyncEqualityMap<K, V> implements AsyncEqualityMap<K, V> {
readonly #map = new Map<K, V>();
get size() {
return this.#map.size;
}
async get(key: K) {
return this.#map.get(key);
}
@@ -138,12 +187,24 @@ class NativeAsyncEqualityMap<K, V> implements AsyncEqualityMap<K, V> {
return existing;
}
async clear() {
clear() {
this.#map.clear();
}
[Symbol.asyncIterator]() {
return asAsyncGenerator(this.#map[Symbol.iterator]());
keys() {
return this.#map.keys();
}
values() {
return this.#map.values();
}
entries() {
return this.#map.entries();
}
[Symbol.iterator]() {
return this.#map[Symbol.iterator]();
}
}
@@ -155,6 +216,10 @@ class CustomAsyncEqualityMap<K, V> implements AsyncEqualityMap<K, V> {
this.#keyComparer = keyComparer;
}
get size() {
return this.#list.length;
}
async get(key: K) {
for (const entry of this.#list) {
if (await this.#keyComparer(key, entry[0])) {
@@ -200,12 +265,30 @@ class CustomAsyncEqualityMap<K, V> implements AsyncEqualityMap<K, V> {
return undefined;
}
async clear() {
clear() {
this.#list.length = 0;
}
[Symbol.asyncIterator]() {
return asAsyncGenerator(this.#list[Symbol.iterator]());
*keys() {
for (const entry of this.#list) {
yield entry[0];
}
}
*values() {
for (const entry of this.#list) {
yield entry[1];
}
}
entries() {
return this[Symbol.iterator]();
}
*[Symbol.iterator]() {
for (const entry of this.#list) {
yield [entry[0], entry[1]] as [K, V]; // no entry mutation allowed!
}
}
}

View File

@@ -1,5 +1,4 @@
import { Equater, MaybeAsyncEquater } from "./types.js";
import { asAsyncGenerator } from "./utils.js";
export interface EqualitySet<T> extends Iterable<T> {
readonly size: number;
@@ -7,6 +6,7 @@ export interface EqualitySet<T> extends Iterable<T> {
contains(obj: T): boolean;
remove(obj: T): boolean;
clear(): void;
values(): IterableIterator<T>;
}
class NativeEqualitySet<T> implements EqualitySet<T> {
@@ -34,6 +34,10 @@ class NativeEqualitySet<T> implements EqualitySet<T> {
this.#set.clear();
}
values() {
return this.#set.values();
}
[Symbol.iterator]() {
return this.#set[Symbol.iterator]();
}
@@ -88,6 +92,10 @@ class CustomEqualitySet<T> implements EqualitySet<T> {
this.#list.length = 0;
}
values() {
return this[Symbol.iterator]();
}
[Symbol.iterator]() {
return this.#list[Symbol.iterator]();
}
@@ -97,12 +105,13 @@ export function createEqualitySet<T>(equater?: Equater<T>): EqualitySet<T> {
return equater ? new CustomEqualitySet(equater) : new NativeEqualitySet<T>();
}
export interface AsyncEqualitySet<T> extends AsyncIterable<T> {
export interface AsyncEqualitySet<T> extends Iterable<T> {
readonly size: number;
add(obj: T): Promise<boolean>;
contains(obj: T): Promise<boolean>;
remove(obj: T): Promise<boolean>;
clear(): Promise<void>;
clear(): void;
values(): IterableIterator<T>;
}
class NativeAsyncEqualitySet<T> implements AsyncEqualitySet<T> {
@@ -126,12 +135,16 @@ class NativeAsyncEqualitySet<T> implements AsyncEqualitySet<T> {
return this.#set.delete(obj);
}
async clear() {
clear() {
this.#set.clear();
}
[Symbol.asyncIterator]() {
return asAsyncGenerator(this.#set[Symbol.iterator]());
values() {
return this.#set.values();
}
[Symbol.iterator]() {
return this.#set[Symbol.iterator]();
}
}
@@ -180,12 +193,16 @@ class CustomAsyncEqualitySet<T> implements AsyncEqualitySet<T> {
return false;
}
async clear() {
clear() {
this.#list.length = 0;
}
[Symbol.asyncIterator]() {
return asAsyncGenerator(this.#list[Symbol.iterator]());
values() {
return this[Symbol.iterator]();
}
[Symbol.iterator]() {
return this.#list[Symbol.iterator]();
}
}

View File

@@ -454,6 +454,14 @@ export abstract class BaseSequence<TElement> extends SequenceMarker implements S
return new OrderBySequence<TElement, TBy>(this, true, selector, comparer);
}
partition(equater?: Equater<TElement>): Sequence<TElement[]> {
return new PartitionSequence<TElement>(this, equater);
}
partitionBy<TBy>(selector: Converter<TElement, TBy>, equater?: Equater<TBy>): Sequence<TElement[]> {
return new PartitionBySequence<TElement, TBy>(this, selector, equater);
}
distinct(equater?: Equater<TElement>): Sequence<TElement> {
return new DistinctSequence<TElement>(this, equater);
}
@@ -833,6 +841,14 @@ export class DelegatedSequence<TElement> extends SequenceMarker implements Seque
return this.#sequence.orderByDescending(selector, comparer);
}
partition(equater?: Equater<TElement> | undefined): Sequence<TElement[]> {
return this.#sequence.partition(equater);
}
partitionBy<TBy>(selector: Converter<TElement, TBy>, equater?: Equater<TBy> | undefined): Sequence<TElement[]> {
return this.#sequence.partitionBy(selector, equater);
}
distinct(equater?: Equater<TElement>) {
return this.#sequence.distinct(equater);
}
@@ -1456,7 +1472,7 @@ export class ConcatSequence<T> extends BaseSequence<T> {
}
}
export class DistinctSequence<T> extends BaseSequence<T> {
class DistinctSequence<T> extends BaseSequence<T> {
readonly #sequence: Sequence<T>;
readonly #equater: Equater<T> | undefined;
@@ -1482,7 +1498,7 @@ export class DistinctSequence<T> extends BaseSequence<T> {
}
}
export class DistinctBySequence<T, U> extends BaseSequence<T> {
class DistinctBySequence<T, U> extends BaseSequence<T> {
readonly #sequence: Sequence<T>;
readonly #selector: Converter<T, U>;
readonly #equater: Equater<U> | undefined;
@@ -1510,7 +1526,7 @@ export class DistinctBySequence<T, U> extends BaseSequence<T> {
}
}
export class WhereSequence<TElement, TFiltered extends TElement> extends BaseSequence<TFiltered> {
class WhereSequence<TElement, TFiltered extends TElement> extends BaseSequence<TFiltered> {
readonly #sequence: Sequence<TElement>;
readonly #predicate: FilterPredicate<TElement, TFiltered>;
@@ -1534,7 +1550,7 @@ export class WhereSequence<TElement, TFiltered extends TElement> extends BaseSeq
}
}
export class SelectManySequence<T, U> extends BaseSequence<U> {
class SelectManySequence<T, U> extends BaseSequence<U> {
readonly #sequence: Sequence<T>;
readonly #converter: Converter<T, Iterable<U>>;
@@ -1552,7 +1568,7 @@ export class SelectManySequence<T, U> extends BaseSequence<U> {
}
}
export class IndexedSequence<T> extends BaseSequence<[number, T]> {
class IndexedSequence<T> extends BaseSequence<[number, T]> {
readonly #sequence: Sequence<T>;
constructor(sequence: Sequence<T>) {
@@ -1578,7 +1594,7 @@ export class IndexedSequence<T> extends BaseSequence<[number, T]> {
}
}
export class SelectSequence<T, U> extends BaseSequence<U> {
class SelectSequence<T, U> extends BaseSequence<U> {
readonly #sequence: Sequence<T>;
readonly #converter: Converter<T, U>;
@@ -1604,7 +1620,7 @@ export class SelectSequence<T, U> extends BaseSequence<U> {
}
}
export class SkipWhileSequence<T> extends BaseSequence<T> {
class SkipWhileSequence<T> extends BaseSequence<T> {
readonly #sequence: Sequence<T>;
readonly #predicate: Predicate<T>;
@@ -1633,7 +1649,7 @@ export class SkipWhileSequence<T> extends BaseSequence<T> {
}
}
export class SkipLastSequence<T> extends BaseSequence<T> {
class SkipLastSequence<T> extends BaseSequence<T> {
readonly #sequence: Sequence<T>;
readonly #n: number;
@@ -1678,7 +1694,7 @@ export class SkipLastSequence<T> extends BaseSequence<T> {
}
}
export class SkipSequence<T> extends BaseSequence<T> {
class SkipSequence<T> extends BaseSequence<T> {
readonly #sequence: Sequence<T>;
readonly #n: number;
@@ -1714,7 +1730,7 @@ export class SkipSequence<T> extends BaseSequence<T> {
}
}
export class TakeWhileSequence<T> extends BaseSequence<T> {
class TakeWhileSequence<T> extends BaseSequence<T> {
readonly #sequence: Sequence<T>;
readonly #predicate: Predicate<T>;
@@ -1740,7 +1756,7 @@ export class TakeWhileSequence<T> extends BaseSequence<T> {
}
}
export class TakeLastSequence<T> extends BaseSequence<T> {
class TakeLastSequence<T> extends BaseSequence<T> {
readonly #sequence: Sequence<T>;
readonly #n: number;
@@ -1771,7 +1787,7 @@ export class TakeLastSequence<T> extends BaseSequence<T> {
}
}
export class TakeSequence<T> extends BaseSequence<T> {
class TakeSequence<T> extends BaseSequence<T> {
readonly #sequence: Sequence<T>;
readonly #n: number;
@@ -1808,13 +1824,13 @@ export class TakeSequence<T> extends BaseSequence<T> {
}
}
export class OrderSequence<T> extends BaseOrderedSequence<T> {
class OrderSequence<T> extends BaseOrderedSequence<T> {
constructor(sequence: Sequence<T>, descending: boolean, sorter?: Comparer<T>) {
super(sequence, sorter, descending);
}
}
export class OrderBySequence<T, U> extends BaseOrderedSequence<T> {
class OrderBySequence<T, U> extends BaseOrderedSequence<T> {
constructor(sequence: Sequence<T>, descending: boolean, selector: Converter<T, U>, sorter?: Comparer<U>) {
super(sequence, OrderBySequence.#createSorter(selector, sorter), descending);
}
@@ -1825,13 +1841,13 @@ export class OrderBySequence<T, U> extends BaseOrderedSequence<T> {
}
}
export class ThenOrderSequence<T> extends BaseOrderedSequence<T> {
class ThenOrderSequence<T> extends BaseOrderedSequence<T> {
constructor(sequence: OrderedSequence<T>, descending: boolean, sorter?: Comparer<T>) {
super(sequence, combineComparers(sequence.comparer ?? defaultArrayComparer, sorter ?? defaultArrayComparer), descending);
}
}
export class ThenOrderBySequence<T, U> extends BaseOrderedSequence<T> {
class ThenOrderBySequence<T, U> extends BaseOrderedSequence<T> {
constructor(sequence: OrderedSequence<T>, descending: boolean, selector: Converter<T, U>, sorter?: Comparer<U>) {
super(sequence, ThenOrderBySequence.#createCombinedSorter(sequence.comparer, selector, sorter), descending);
}
@@ -1843,7 +1859,7 @@ export class ThenOrderBySequence<T, U> extends BaseOrderedSequence<T> {
}
}
export class AppendSequence<T> extends BaseSequence<T> {
class AppendSequence<T> extends BaseSequence<T> {
readonly #sequence: Sequence<T>;
readonly #obj: T;
@@ -1869,7 +1885,7 @@ export class AppendSequence<T> extends BaseSequence<T> {
}
}
export class PrependSequence<T> extends BaseSequence<T> {
class PrependSequence<T> extends BaseSequence<T> {
readonly #sequence: Sequence<T>;
readonly #obj: T;
@@ -1895,7 +1911,7 @@ export class PrependSequence<T> extends BaseSequence<T> {
}
}
export class PeekSequence<T> extends DelegatedSequence<T> {
class PeekSequence<T> extends DelegatedSequence<T> {
readonly #action: Action<T>;
constructor(sequence: Sequence<T>, action: Action<T>) {
@@ -1912,7 +1928,7 @@ export class PeekSequence<T> extends DelegatedSequence<T> {
}
}
export class ZippedSequence<T, U> extends BaseSequence<[T, U]> {
class ZippedSequence<T, U> extends BaseSequence<[T, U]> {
readonly #first: Sequence<T>;
readonly #second: Sequence<U>;
@@ -1951,7 +1967,7 @@ export class ZippedSequence<T, U> extends BaseSequence<[T, U]> {
}
}
export class UnionSequence<T> extends BaseSequence<T> {
class UnionSequence<T> extends BaseSequence<T> {
readonly #first: Sequence<T>;
readonly #second: Sequence<T>;
readonly #equater: Equater<T> | undefined;
@@ -1984,7 +2000,7 @@ export class UnionSequence<T> extends BaseSequence<T> {
}
}
export class UnionBySequence<T, U> extends BaseSequence<T> {
class UnionBySequence<T, U> extends BaseSequence<T> {
readonly #first: Sequence<T>;
readonly #second: Sequence<T>;
readonly #selector: Converter<T, U>;
@@ -2019,7 +2035,7 @@ export class UnionBySequence<T, U> extends BaseSequence<T> {
}
}
export class ExceptSequence<T> extends BaseSequence<T> {
class ExceptSequence<T> extends BaseSequence<T> {
readonly #first: Sequence<T>;
readonly #second: Sequence<T>;
readonly #equater: Equater<T> | undefined;
@@ -2051,7 +2067,7 @@ export class ExceptSequence<T> extends BaseSequence<T> {
}
}
export class ExceptBySequence<T, U> extends BaseSequence<T> {
class ExceptBySequence<T, U> extends BaseSequence<T> {
readonly #first: Sequence<T>;
readonly #second: Sequence<T>;
readonly #selector: Converter<T, U>;
@@ -2085,7 +2101,7 @@ export class ExceptBySequence<T, U> extends BaseSequence<T> {
}
}
export class IntersectSequence<T> extends BaseSequence<T> {
class IntersectSequence<T> extends BaseSequence<T> {
readonly #first: Sequence<T>;
readonly #second: Sequence<T>;
readonly #equater: Equater<T> | undefined;
@@ -2117,7 +2133,7 @@ export class IntersectSequence<T> extends BaseSequence<T> {
}
}
export class IntersectBySequence<T, U> extends BaseSequence<T> {
class IntersectBySequence<T, U> extends BaseSequence<T> {
readonly #first: Sequence<T>;
readonly #second: Sequence<T>;
readonly #selector: Converter<T, U>;
@@ -2151,7 +2167,7 @@ export class IntersectBySequence<T, U> extends BaseSequence<T> {
}
}
export class ReversedSequence<T> extends BaseSequence<T> {
class ReversedSequence<T> extends BaseSequence<T> {
readonly #sequence: Sequence<T>;
constructor(sequence: Sequence<T>) {
@@ -2181,7 +2197,7 @@ export class ReversedSequence<T> extends BaseSequence<T> {
}
}
export class GroupBySequence<TElement, TKey, TResult> extends BaseSequence<GroupedSequence<TKey, TResult>> {
class GroupBySequence<TElement, TKey, TResult> extends BaseSequence<GroupedSequence<TKey, TResult>> {
readonly #sequence: Sequence<TElement>;
readonly #keySelector: Converter<TElement, TKey>;
readonly #elementSelector: Converter<TElement, TResult>;
@@ -2220,7 +2236,7 @@ export class GroupBySequence<TElement, TKey, TResult> extends BaseSequence<Group
}
}
export class ChunkedSequence<T> extends BaseSequence<T[]> {
class ChunkedSequence<T> extends BaseSequence<T[]> {
readonly #sequence: Sequence<T>;
readonly #size: number;
@@ -2258,7 +2274,7 @@ export class ChunkedSequence<T> extends BaseSequence<T[]> {
}
}
export class JoinSequence<TOuter, TInner, TKey, TResult> extends BaseSequence<TResult> {
class JoinSequence<TOuter, TInner, TKey, TResult> extends BaseSequence<TResult> {
readonly #first: Sequence<TOuter>;
readonly #second: Sequence<TInner>;
readonly #firstKeySelector: Converter<TOuter, TKey>;
@@ -2300,7 +2316,7 @@ export class JoinSequence<TOuter, TInner, TKey, TResult> extends BaseSequence<TR
}
}
export class GroupJoinSequence<TOuter, TInner, TKey, TResult> extends BaseSequence<TResult> {
class GroupJoinSequence<TOuter, TInner, TKey, TResult> extends BaseSequence<TResult> {
readonly #first: Sequence<TOuter>;
readonly #second: Sequence<TInner>;
readonly #firstKeySelector: Converter<TOuter, TKey>;
@@ -2349,7 +2365,7 @@ export class GroupJoinSequence<TOuter, TInner, TKey, TResult> extends BaseSequen
}
}
export class RemoveSequence<T> extends BaseSequence<T> {
class RemoveSequence<T> extends BaseSequence<T> {
readonly #sequence: Sequence<T>;
readonly #obj: T;
readonly #all: boolean;
@@ -2388,7 +2404,7 @@ export class RemoveSequence<T> extends BaseSequence<T> {
}
}
export class CacheSequence<T> extends DelegatedSequence<T> {
class CacheSequence<T> extends DelegatedSequence<T> {
#cached = false;
constructor(sequence: Sequence<T>) {
@@ -2404,3 +2420,62 @@ export class CacheSequence<T> extends DelegatedSequence<T> {
return super.iterator();
}
}
class PartitionSequence<T> extends BaseSequence<T[]> {
readonly #sequence: Sequence<T>;
readonly #equater: Equater<T>;
constructor(sequence: Sequence<T>, equater: Equater<T> | undefined) {
super();
this.#sequence = sequence;
this.#equater = equater ?? strictEquals;
}
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]);
}
}
yield* partitions.values();
}
}
class PartitionBySequence<TElement, TBy> extends BaseSequence<TElement[]> {
readonly #sequence: Sequence<TElement>;
readonly #selector: Converter<TElement, TBy>;
readonly #equater: Equater<TBy>;
constructor(sequence: Sequence<TElement>, selector: Converter<TElement, TBy>, equater: Equater<TBy> | undefined) {
super();
this.#sequence = sequence;
this.#selector = selector;
this.#equater = equater ?? strictEquals;
}
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]);
}
}
yield* partitions.values();
}
}

View File

@@ -67,6 +67,9 @@ export interface Sequence<TElement> extends Iterable<TElement> {
orderDescending(comparer?: Comparer<TElement>): OrderedSequence<TElement>;
orderByDescending<TBy>(selector: Converter<TElement, TBy>, comparer?: Comparer<TBy>): OrderedSequence<TElement>;
partition(equater?: Equater<TElement>): Sequence<TElement[]>;
partitionBy<TBy>(selector: Converter<TElement, TBy>, equater?: Equater<TBy>): Sequence<TElement[]>;
distinct(equater?: Equater<TElement>): Sequence<TElement>;
distinctBy<TBy>(selector: Converter<TElement, TBy>, equater?: Equater<TBy>): Sequence<TElement>;