add sequence partition operation
This commit is contained in:
@@ -456,6 +456,14 @@ export abstract class BaseAsyncSequence<TElement> extends AsyncSequenceMarker im
|
|||||||
return new OrderByAsyncSequence<TElement, TBy>(this, true, selector, comparer);
|
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> {
|
distinct(equater?: MaybeAsyncEquater<TElement>): AsyncSequence<TElement> {
|
||||||
return new DistinctAsyncSequence<TElement>(this, equater);
|
return new DistinctAsyncSequence<TElement>(this, equater);
|
||||||
}
|
}
|
||||||
@@ -849,6 +857,14 @@ export class DelegatedAsyncSequence<TElement> extends AsyncSequenceMarker implem
|
|||||||
return this.#sequence.orderByDescending(selector, comparer);
|
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> {
|
distinct(equater?: ((first: TElement, second: TElement) => MaybePromise<boolean>) | undefined): AsyncSequence<TElement> {
|
||||||
return this.#sequence.distinct(equater);
|
return this.#sequence.distinct(equater);
|
||||||
}
|
}
|
||||||
@@ -2141,3 +2157,62 @@ export class CacheAsyncSequence<T> extends BaseAsyncSequence<T> {
|
|||||||
yield* this.#cache ??= await this.#sequence.toArray();
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -66,6 +66,9 @@ export interface AsyncSequence<TElement> extends AsyncIterable<Awaited<TElement>
|
|||||||
orderDescending(comparer?: MaybeAsyncComparer<TElement>): AsyncSequence<TElement>;
|
orderDescending(comparer?: MaybeAsyncComparer<TElement>): AsyncSequence<TElement>;
|
||||||
orderByDescending<TBy>(selector: MaybeAsyncConverter<TElement, TBy>, comparer?: MaybeAsyncComparer<TBy>): 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>;
|
distinct(equater?: MaybeAsyncEquater<TElement>): AsyncSequence<TElement>;
|
||||||
distinctBy<TBy>(selector: MaybeAsyncConverter<TElement, TBy>, equater?: MaybeAsyncEquater<TBy>): AsyncSequence<TElement>;
|
distinctBy<TBy>(selector: MaybeAsyncConverter<TElement, TBy>, equater?: MaybeAsyncEquater<TBy>): AsyncSequence<TElement>;
|
||||||
|
|
||||||
|
|||||||
@@ -454,6 +454,14 @@ export abstract class BaseSequence<TElement> extends SequenceMarker implements S
|
|||||||
return new OrderBySequence<TElement, TBy>(this, true, selector, comparer);
|
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> {
|
distinct(equater?: Equater<TElement>): Sequence<TElement> {
|
||||||
return new DistinctSequence<TElement>(this, equater);
|
return new DistinctSequence<TElement>(this, equater);
|
||||||
}
|
}
|
||||||
@@ -833,6 +841,14 @@ export class DelegatedSequence<TElement> extends SequenceMarker implements Seque
|
|||||||
return this.#sequence.orderByDescending(selector, comparer);
|
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>) {
|
distinct(equater?: Equater<TElement>) {
|
||||||
return this.#sequence.distinct(equater);
|
return this.#sequence.distinct(equater);
|
||||||
}
|
}
|
||||||
@@ -2404,3 +2420,62 @@ export class CacheSequence<T> extends DelegatedSequence<T> {
|
|||||||
return super.iterator();
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -67,6 +67,9 @@ export interface Sequence<TElement> extends Iterable<TElement> {
|
|||||||
orderDescending(comparer?: Comparer<TElement>): OrderedSequence<TElement>;
|
orderDescending(comparer?: Comparer<TElement>): OrderedSequence<TElement>;
|
||||||
orderByDescending<TBy>(selector: Converter<TElement, TBy>, comparer?: Comparer<TBy>): 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>;
|
distinct(equater?: Equater<TElement>): Sequence<TElement>;
|
||||||
distinctBy<TBy>(selector: Converter<TElement, TBy>, equater?: Equater<TBy>): Sequence<TElement>;
|
distinctBy<TBy>(selector: Converter<TElement, TBy>, equater?: Equater<TBy>): Sequence<TElement>;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user