geninq
Version:
A JavaScript version of the Linq library for Generators
210 lines (201 loc) • 8.05 kB
text/typescript
import { IsFunction } from "@paulpopat/safe-type";
import { FakeHash } from "../fake-hash";
import { Build, Promised } from "./utils";
declare global {
interface Generator<T = unknown, TReturn = any, TNext = unknown> {
/**
* Groups the elements of a sequence according to a specified key selector function.
* @param builder A function to extract the key for each element.
* @returns A collection of elements of the type specified where each element represents a projection over a group and its key.
*/
group_by<
TKey extends string | number | boolean,
TElement = T,
TResult = [TKey, Generator<TElement>]
>(
builder: (item: T) => TKey
): Generator<TResult, TReturn, TNext>;
/**
* Groups the elements of a sequence according to a specified key selector function
* and projects the elements for each group by using a specified function.
* @param builder.key A function to extract the key for each element.
* @param builder.element A function to map each source element to an element in an grouping.
* @returns A collection of elements of the type specified where each element represents a projection over a group and its key.
*/
group_by<
TKey extends string | number | boolean,
TElement = T,
TResult = [TKey, Generator<TElement>]
>(builder: {
key: (item: T) => TKey;
element?: (item: T) => TElement;
}): Generator<TResult, TReturn, TNext>;
/**
* Groups the elements of a sequence according to a key selector function.
* The keys are compared by using a comparer and each group's elements are
* projected by using a specified function.
* @param builder.key A function to extract the key for each element.
* @param builder.element A function to map each source element to an element in an grouping.
* @param comparitor A comparitor function to compare keys with.
* @returns A collection of elements of the type specified where each element represents a projection over a group and its key.
*/
group_by<TKey, TElement = T, TResult = [TKey, Generator<TElement>]>(
builder: {
key: (item: T) => TKey;
element?: (item: T) => TElement;
},
comparitor: (a: TKey, b: TKey) => boolean
): Generator<TResult, TReturn, TNext>;
/**
* Groups the elements of a sequence according to a specified key selector
* function and compares the keys by using a specified comparer.
* @param builder A function to extract the key for each element.
* @param comparitor A comparitor function to compare keys with.
* @returns A collection of elements of the type specified where each element represents a projection over a group and its key.
*/
group_by<TKey, TElement = T, TResult = [TKey, Generator<TElement>]>(
builder: (item: T) => TKey,
comparitor: (a: TKey, b: TKey) => boolean
): Generator<TResult, TReturn, TNext>;
}
interface AsyncGenerator<T = unknown, TReturn = any, TNext = unknown> {
/**
* Groups the elements of a sequence according to a specified key selector function.
* @param builder A function to extract the key for each element.
* @returns A collection of elements of the type specified where each element represents a projection over a group and its key.
*/
group_by<
TKey extends string | number | boolean,
TElement = T,
TResult = [TKey, AsyncGenerator<TElement>]
>(
builder: (item: T) => Promised<TKey>
): AsyncGenerator<TResult, TReturn, TNext>;
/**
* Groups the elements of a sequence according to a specified key selector function
* and projects the elements for each group by using a specified function.
* @param builder.key A function to extract the key for each element.
* @param builder.element A function to map each source element to an element in an grouping.
* @returns A collection of elements of the type specified where each element represents a projection over a group and its key.
*/
group_by<
TKey extends string | number | boolean,
TElement = T,
TResult = [TKey, AsyncGenerator<TElement>]
>(builder: {
key: (item: T) => Promised<TKey>;
element?: (item: T) => Promised<TElement>;
}): AsyncGenerator<TResult, TReturn, TNext>;
/**
* Groups the elements of a sequence according to a key selector function.
* The keys are compared by using a comparer and each group's elements are
* projected by using a specified function.
* @param builder.key A function to extract the key for each element.
* @param builder.element A function to map each source element to an element in an grouping.
* @param comparitor A comparitor function to compare keys with.
* @returns A collection of elements of the type specified where each element represents a projection over a group and its key.
*/
group_by<TKey, TElement = T, TResult = [TKey, AsyncGenerator<TElement>]>(
builder: (item: T) => Promised<TKey>,
comparitor: (a: TKey, b: TKey) => boolean
): AsyncGenerator<TResult, TReturn, TNext>;
/**
* Groups the elements of a sequence according to a specified key selector
* function and compares the keys by using a specified comparer.
* @param builder A function to extract the key for each element.
* @param comparitor A comparitor function to compare keys with.
* @returns A collection of elements of the type specified where each element represents a projection over a group and its key.
*/
group_by<TKey, TElement = T, TResult = [TKey, AsyncGenerator<TElement>]>(
builder: {
key: (item: T) => Promised<TKey>;
element?: (item: T) => Promised<TElement>;
},
comparitor: (a: TKey, b: TKey) => boolean
): AsyncGenerator<TResult, TReturn, TNext>;
}
}
function CreateBuilder(
builder:
| ((item: unknown) => unknown)
| {
key: (item: unknown) => unknown;
element?: (item: unknown) => unknown;
}
): {
key: (item: unknown) => unknown;
element: (item: unknown) => unknown;
};
function CreateBuilder(
builder:
| ((item: unknown) => Promised<unknown>)
| {
key: (item: unknown) => Promised<unknown>;
element?: (item: unknown) => Promised<unknown>;
}
): {
key: (item: unknown) => Promised<unknown>;
element: (item: unknown) => Promised<unknown>;
};
function CreateBuilder(builder: any) {
return IsFunction(builder)
? {
key: builder,
element: (i: any) => i,
}
: {
key: builder.key,
element: builder.element ?? ((i: any) => i),
};
}
Build(
"group_by",
function* (builder, comparitor = (a, b) => a === b) {
const internal = this.array();
const b = CreateBuilder(builder);
const hash = FakeHash(comparitor);
for (const item of internal) {
const key = b.key(item);
if (hash.contains(key)) {
continue;
}
hash.add(key);
yield [
key,
(function* () {
for (let i = 0; i < internal.length; i++) {
const item = internal[i];
const bkey = b.key(item);
if (comparitor(key, bkey)) {
yield b.element(item);
}
}
})(),
];
}
},
async function* (builder, comparitor = (a, b) => a === b) {
const internal = await this.array();
const b = CreateBuilder(builder);
const hash = FakeHash(comparitor);
for (const item of internal) {
const key = await Promise.resolve(b.key(item));
if (hash.contains(key)) {
continue;
}
hash.add(key);
yield [
key,
(async function* () {
for (let i = 0; i < internal.length; i++) {
const item = internal[i];
const bkey = b.key(item);
if (comparitor(key, bkey)) {
yield await Promise.resolve(b.element(item));
}
}
})(),
];
}
}
);