1
0
This commit is contained in:
2025-09-10 10:21:37 +02:00
parent 637991c394
commit 806d735c35
20 changed files with 480 additions and 259 deletions

View File

@@ -1,10 +1,10 @@
import { Collector } from "../collector/types.js";
import { asAsyncComparer, combineNullableAsyncComparers, createAsyncComparerUsing, defaultAsyncComparer } from "../comparer/async.js";
import { MaybeAsyncComparisonOrComparer, AsyncComparer } from "../comparer/types.js";
import { strictEquals } from "../equality-comparer/index.js";
import { strictEquals } from "../equality-comparer/sync.js";
import { MaybeAsyncEqualityComparison } from "../equality-comparer/types.js";
import { createAsyncEqualityMap } from "../equality-map.js";
import { createAsyncEqualitySet } from "../equality-set.js";
import { createAsyncEqualityMap } from "../equality-map/index.js";
import { createAsyncEqualitySet } from "../equality-set/index.js";
import { createQueue } from "../queue.js";
import { getRandomElementAsync } from "../random/index.js";
import { AsyncRandomOptions } from "../random/types.js";

View File

@@ -15,11 +15,11 @@ export function asComparison<T>(comparer: ComparisonOrComparer<T>) {
return typeof comparer === "function" ? comparer : comparer.comparison();
}
export function createComparer<T>(comparison: Comparison<T>): Comparer<T> {
export function createComparer<T = any>(comparison: Comparison<T>): Comparer<T> {
return new SimpleComparer(comparison);
}
export function createComparerUsing<T, U>(projection: Converter<T, U>, comparison?: ComparisonOrComparer<U>): Comparer<T> {
export function createComparerUsing<T = any, U = any>(projection: Converter<T, U>, comparison?: ComparisonOrComparer<U>): Comparer<T> {
return new MappedComparer(projection, comparison);
}

View File

@@ -24,12 +24,9 @@ export interface AsyncComparer<T> {
export type Comparison<T> = (first: T, second: T) => number;
export type ComparisonOrComparer<T> = Comparison<T> | Comparer<T>;
export type Equater<T> = (first: T, second: T) => boolean;
export type AsyncComparison<T> = AsyncFunction<Comparison<T>>;
export type MaybeAsyncComparison<T> = MaybeAsyncFunction<Comparison<T>>;
export type AsyncComparisonOrComparer<T> = AsyncComparison<T> | AsyncComparer<T>;
export type MaybeAsyncComparisonOrComparer<T> = MaybeAsyncComparison<T> | Comparer<T> | AsyncComparer<T>;
export type AsyncEquater<T> = AsyncFunction<Equater<T>>;
export type MaybeAsyncEquater<T> = MaybeAsyncFunction<Equater<T>>;

View File

@@ -1,11 +0,0 @@
export function looseEquals<T>(a: T, b: T) {
return a == b;
}
export function strictEquals<T>(a: T, b: T) {
return a === b;
}
export function sameValue<T>(a: T, b: T) {
return Object.is(a, b);
}

View File

@@ -0,0 +1,167 @@
import { Converter } from "../types.js";
import { Nullable } from "../utils.js";
import { EqualityComparer, EqualityComparison, EqualityComparisonOrComparer } from "./types.js";
export function looseEquals<T>(a: T, b: T) {
return a == b;
}
export function strictEquals<T>(a: T, b: T) {
return a === b;
}
export function sameValue<T>(a: T, b: T) {
return Object.is(a, b);
}
export function isEqualityComparer<T>(obj: any): obj is EqualityComparer<T> {
return obj instanceof BaseEqualityComparer;
}
export function asEqualityComparer<T>(equalityComparer: EqualityComparisonOrComparer<T>) {
return typeof equalityComparer === "function" ? createEqualityComparer(equalityComparer) : equalityComparer;
}
export function asEqualityComparison<T>(equalityComparer: EqualityComparisonOrComparer<T>) {
return typeof equalityComparer === "function" ? equalityComparer : equalityComparer.equalityComparison();
}
export function createEqualityComparer<T = any>(equalityComparison: EqualityComparison<T>): EqualityComparer<T> {
return new SimpleEqualityComparer(equalityComparison);
}
export function createEqualityComparerUsing<T = any, U = any>(projection: Converter<T, U>, equalityComparison?: EqualityComparisonOrComparer<U>): EqualityComparer<T> {
return new MappedEqualityComparer(projection, equalityComparison);
}
export function oppositeEqualityComparison<T>(equalityComparison: EqualityComparison<T>): EqualityComparison<T> {
return (a, b) => !equalityComparison(a, b);
}
export function combineNullableEqualityComparers<T>(equalityComparers: Nullable<EqualityComparisonOrComparer<T>>[]) {
let result = defaultEqualityComparer;
for (const equalityComparer of equalityComparers) {
if (!equalityComparer) {
continue;
}
result = result.then(asEqualityComparer(equalityComparer));
}
return result === defaultEqualityComparer ? undefined : result;
}
export abstract class BaseEqualityComparer<T> implements EqualityComparer<T> {
#cachedBoundEqualityComparison: EqualityComparison<T> | undefined;
public abstract equals(a: T, b: T): boolean;
public equalityComparison(): EqualityComparison<T> {
return this.#cachedBoundEqualityComparison ??= this.equals.bind(this);
}
public opposite(): EqualityComparer<T> {
return new OppositeEqualityComparer(this);
}
public then(equalityComparer: EqualityComparer<T>): EqualityComparer<T> {
return new ThenEqualityComparer(this, equalityComparer);
}
public thenEquals(equalityComparison: EqualityComparison<T>): EqualityComparer<T> {
return this.then(createEqualityComparer(equalityComparison));
}
public thenEqualsUsing<U>(projection: Converter<T, U>, equalityComparison?: EqualityComparisonOrComparer<U>): EqualityComparer<T> {
return this.then(createEqualityComparerUsing(projection, equalityComparison));
}
}
class SimpleEqualityComparer<T> extends BaseEqualityComparer<T> {
readonly #equalityComparison: EqualityComparison<T>;
public constructor(equalityComparison: EqualityComparison<T>) {
super();
this.#equalityComparison = equalityComparison;
}
public override equals(a: T, b: T): boolean {
return this.#equalityComparison(a, b);
}
public override equalityComparison() {
return this.#equalityComparison;
}
}
class MappedEqualityComparer<T, U> extends BaseEqualityComparer<T> {
readonly #projection: Converter<T, U>;
readonly #equalityComparison: EqualityComparer<U>;
public constructor(projection: Converter<T, U>, equalityComparison?: EqualityComparisonOrComparer<U>) {
super();
this.#projection = projection;
this.#equalityComparison = equalityComparison ? asEqualityComparer(equalityComparison) : defaultEqualityComparer;
}
public override equals(a: T, b: T): boolean {
return this.#equalityComparison.equals(this.#projection(a), this.#projection(b));
}
}
class OppositeEqualityComparer<T> extends BaseEqualityComparer<T> {
readonly #base: EqualityComparer<T>;
public constructor(base: EqualityComparer<T>) {
super();
this.#base = base;
}
public override equals(a: T, b: T): boolean {
return !this.#base.equals(a, b);
}
public override opposite(): EqualityComparer<T> {
return this.#base;
}
}
class ThenEqualityComparer<T> extends BaseEqualityComparer<T> {
readonly #base: EqualityComparer<T>;
readonly #equalityComparer: EqualityComparer<T>;
public constructor(base: EqualityComparer<T>, equalityComparer: EqualityComparer<T>) {
super();
this.#base = base;
this.#equalityComparer = equalityComparer;
}
public override equals(a: T, b: T) {
return this.#base.equals(a, b) && this.#equalityComparer.equals(a, b);
}
}
export const defaultEqualityComparer: EqualityComparer<any> = new class DefaultEqualityComparer extends BaseEqualityComparer<any> {
public override equals(a: any, b: any): boolean {
return a === b;
}
};
export function getDefaultComparer<T>(): EqualityComparer<T> {
return defaultEqualityComparer;
}
export const dateComparer: EqualityComparer<Date> = new class DateEqualityComparer extends BaseEqualityComparer<Date> {
public override equals(a: Date, b: Date): boolean {
return a.getTime() === b.getTime();
}
};
export const looseEqualsComparer: EqualityComparer<any> = new SimpleEqualityComparer<any>(looseEquals);
export const strictEqualsComparer: EqualityComparer<any> = new SimpleEqualityComparer<any>(strictEquals);
export const sameValueComparer: EqualityComparer<any> = new SimpleEqualityComparer<any>(sameValue);

View File

@@ -1,6 +1,15 @@
import { AsyncFunction, MaybeAsyncFunction } from "../types.js";
import { Converter, MaybeAsyncFunction } from "../types.js";
export interface EqualityComparer<T> {
equals(a: T, b: T): boolean;
equalityComparison(): EqualityComparison<T>;
opposite(): EqualityComparer<T>;
then(equalityComparer: EqualityComparer<T>): EqualityComparer<T>;
thenEquals(equalityComparison: EqualityComparison<T>): EqualityComparer<T>;
thenEqualsUsing<U>(projection: Converter<T, U>, equalityComparison?: EqualityComparisonOrComparer<U>): EqualityComparer<T>;
}
export type EqualityComparison<T> = (first: T, second: T) => boolean;
export type EqualityComparisonOrComparer<T> = EqualityComparison<T> | EqualityComparer<T>;
export type AsyncEqualityComparison<T> = AsyncFunction<EqualityComparison<T>>;
export type MaybeAsyncEqualityComparison<T> = MaybeAsyncFunction<EqualityComparison<T>>;

View File

@@ -1,22 +1,9 @@
import { EqualityComparison, MaybeAsyncEqualityComparison } from "./equality-comparer/types.js";
import { MaybeAsyncIterable } from "./types.js";
import { asEqualityComparer } from "../equality-comparer/sync.js";
import { EqualityComparer, EqualityComparisonOrComparer, MaybeAsyncEqualityComparison } from "../equality-comparer/types.js";
import { MaybeAsyncIterable } from "../types.js";
import { AsyncEqualityMap, EqualityMap, EqualityMapEntry } from "./types.js";
export type Entry<K, V> = [key: K, value: V];
export interface EqualityMap<K, V> extends Iterable<Entry<K, V>> {
readonly size: number;
get(key: K): V | undefined;
set(key: K, value: V): V | undefined;
setAll(entries: Iterable<Entry<K, V>>): void;
contains(key: K): boolean;
remove(key: K): V | undefined;
clear(): void;
keys(): IterableIterator<K>;
values(): IterableIterator<V>;
entries(): IterableIterator<Entry<K, V>>;
}
class NativeEqualityMap<K, V> implements EqualityMap<K, V> {
export class NativeEqualityMap<K, V> implements EqualityMap<K, V> {
readonly #map = new Map<K, V>();
get size() {
@@ -33,7 +20,7 @@ class NativeEqualityMap<K, V> implements EqualityMap<K, V> {
return existing;
}
setAll(entries: Iterable<Entry<K, V>>) {
setAll(entries: Iterable<EqualityMapEntry<K, V>>) {
for (const [key, value] of entries) {
this.set(key, value);
}
@@ -70,12 +57,12 @@ class NativeEqualityMap<K, V> implements EqualityMap<K, V> {
}
}
class CustomEqualityMap<K, V> implements EqualityMap<K, V> {
readonly #list: Entry<K, V>[] = [];
readonly #keyComparer: EqualityComparison<K>;
export class CustomEqualityMap<K, V> implements EqualityMap<K, V> {
readonly #list: EqualityMapEntry<K, V>[] = [];
readonly #keyComparer: EqualityComparer<K>;
constructor(keyComparer: EqualityComparison<K>) {
this.#keyComparer = keyComparer;
constructor(keyComparer: EqualityComparisonOrComparer<K>) {
this.#keyComparer = asEqualityComparer(keyComparer);
}
get size() {
@@ -84,7 +71,7 @@ class CustomEqualityMap<K, V> implements EqualityMap<K, V> {
get(key: K) {
for (const entry of this.#list) {
if (this.#keyComparer(key, entry[0])) {
if (this.#keyComparer.equals(key, entry[0])) {
return entry[1];
}
}
@@ -94,7 +81,7 @@ class CustomEqualityMap<K, V> implements EqualityMap<K, V> {
set(key: K, value: V) {
for (const entry of this.#list) {
if (this.#keyComparer(key, entry[0])) {
if (this.#keyComparer.equals(key, entry[0])) {
const previous = entry[1];
entry[1] = value;
return previous;
@@ -106,7 +93,7 @@ class CustomEqualityMap<K, V> implements EqualityMap<K, V> {
return undefined;
}
setAll(entries: Iterable<Entry<K, V>>) {
setAll(entries: Iterable<EqualityMapEntry<K, V>>) {
for (const [key, value] of entries) {
this.set(key, value);
}
@@ -114,7 +101,7 @@ class CustomEqualityMap<K, V> implements EqualityMap<K, V> {
contains(key: K) {
for (const entry of this.#list) {
if (this.#keyComparer(key, entry[0])) {
if (this.#keyComparer.equals(key, entry[0])) {
return true;
}
}
@@ -124,7 +111,7 @@ class CustomEqualityMap<K, V> implements EqualityMap<K, V> {
remove(key: K) {
for (let i = 0; i < this.#list.length; i++) {
if (this.#keyComparer(key, this.#list[i][0])) {
if (this.#keyComparer.equals(key, this.#list[i][0])) {
const removed = this.#list.splice(i, 1);
return removed[0][1];
}
@@ -155,29 +142,12 @@ class CustomEqualityMap<K, V> implements EqualityMap<K, V> {
*[Symbol.iterator]() {
for (const entry of this.#list) {
yield entry.slice() as Entry<K, V>; // no entry mutation allowed!
yield entry.slice() as EqualityMapEntry<K, V>; // no entry mutation allowed!
}
}
}
export function createEqualityMap<K, V>(keyComparer?: EqualityComparison<K>): EqualityMap<K, V> {
return keyComparer ? new CustomEqualityMap<K, V>(keyComparer) : new NativeEqualityMap<K, V>();
}
export interface AsyncEqualityMap<K, V> extends Iterable<Entry<K, V>> {
readonly size: number;
get(key: K): Promise<V | undefined>;
set(key: K, value: V): Promise<V | undefined>;
setAll(entries: MaybeAsyncIterable<Entry<K, V>>): Promise<void>;
contains(key: K): Promise<boolean>;
remove(key: K): Promise<V | undefined>;
clear(): void;
keys(): IterableIterator<K>;
values(): IterableIterator<V>;
entries(): IterableIterator<Entry<K, V>>;
}
class NativeAsyncEqualityMap<K, V> implements AsyncEqualityMap<K, V> {
export class NativeAsyncEqualityMap<K, V> implements AsyncEqualityMap<K, V> {
readonly #map = new Map<K, V>();
get size() {
@@ -194,7 +164,7 @@ class NativeAsyncEqualityMap<K, V> implements AsyncEqualityMap<K, V> {
return existing;
}
async setAll(entries: MaybeAsyncIterable<Entry<K, V>>) {
async setAll(entries: MaybeAsyncIterable<EqualityMapEntry<K, V>>) {
for await (const [key, value] of entries) {
await this.set(key, value);
}
@@ -231,8 +201,8 @@ class NativeAsyncEqualityMap<K, V> implements AsyncEqualityMap<K, V> {
}
}
class CustomAsyncEqualityMap<K, V> implements AsyncEqualityMap<K, V> {
readonly #list: Entry<K, V>[] = [];
export class CustomAsyncEqualityMap<K, V> implements AsyncEqualityMap<K, V> {
readonly #list: EqualityMapEntry<K, V>[] = [];
readonly #keyComparer: MaybeAsyncEqualityComparison<K>;
constructor(keyComparer: MaybeAsyncEqualityComparison<K>) {
@@ -267,7 +237,7 @@ class CustomAsyncEqualityMap<K, V> implements AsyncEqualityMap<K, V> {
return undefined;
}
async setAll(entries: MaybeAsyncIterable<Entry<K, V>>) {
async setAll(entries: MaybeAsyncIterable<EqualityMapEntry<K, V>>) {
for await (const [key, value] of entries) {
await this.set(key, value);
}
@@ -316,11 +286,7 @@ class CustomAsyncEqualityMap<K, V> implements AsyncEqualityMap<K, V> {
*[Symbol.iterator]() {
for (const entry of this.#list) {
yield entry.slice() as Entry<K, V>; // no entry mutation allowed!
yield entry.slice() as EqualityMapEntry<K, V>; // no entry mutation allowed!
}
}
}
export function createAsyncEqualityMap<K, V>(keyComparer?: MaybeAsyncEqualityComparison<K>): AsyncEqualityMap<K, V> {
return keyComparer ? new CustomAsyncEqualityMap<K, V>(keyComparer) : new NativeAsyncEqualityMap<K, V>();
}

11
src/equality-map/index.ts Normal file
View File

@@ -0,0 +1,11 @@
import { EqualityComparisonOrComparer, MaybeAsyncEqualityComparison } from "../equality-comparer/types.js";
import { CustomAsyncEqualityMap, CustomEqualityMap, NativeAsyncEqualityMap, NativeEqualityMap } from "./impl.js";
import { AsyncEqualityMap, EqualityMap } from "./types.js";
export function createEqualityMap<K, V>(keyComparer?: EqualityComparisonOrComparer<K>): EqualityMap<K, V> {
return keyComparer ? new CustomEqualityMap<K, V>(keyComparer) : new NativeEqualityMap<K, V>();
}
export function createAsyncEqualityMap<K, V>(keyComparer?: MaybeAsyncEqualityComparison<K>): AsyncEqualityMap<K, V> {
return keyComparer ? new CustomAsyncEqualityMap<K, V>(keyComparer) : new NativeAsyncEqualityMap<K, V>();
}

29
src/equality-map/types.ts Normal file
View File

@@ -0,0 +1,29 @@
import { MaybeAsyncIterable } from "../types.js";
export type EqualityMapEntry<K, V> = [key: K, value: V];
export interface EqualityMap<K, V> extends Iterable<EqualityMapEntry<K, V>> {
readonly size: number;
get(key: K): V | undefined;
set(key: K, value: V): V | undefined;
setAll(entries: Iterable<EqualityMapEntry<K, V>>): void;
contains(key: K): boolean;
remove(key: K): V | undefined;
clear(): void;
keys(): IterableIterator<K>;
values(): IterableIterator<V>;
entries(): IterableIterator<EqualityMapEntry<K, V>>;
}
export interface AsyncEqualityMap<K, V> extends Iterable<EqualityMapEntry<K, V>> {
readonly size: number;
get(key: K): Promise<V | undefined>;
set(key: K, value: V): Promise<V | undefined>;
setAll(entries: MaybeAsyncIterable<EqualityMapEntry<K, V>>): Promise<void>;
contains(key: K): Promise<boolean>;
remove(key: K): Promise<V | undefined>;
clear(): void;
keys(): IterableIterator<K>;
values(): IterableIterator<V>;
entries(): IterableIterator<EqualityMapEntry<K, V>>;
}

View File

@@ -1,17 +1,9 @@
import { EqualityComparison, MaybeAsyncEqualityComparison } from "./equality-comparer/types.js";
import { MaybeAsyncIterable } from "./types.js";
import { asEqualityComparer } from "../equality-comparer/sync.js";
import { EqualityComparer, EqualityComparisonOrComparer, MaybeAsyncEqualityComparison } from "../equality-comparer/types.js";
import { MaybeAsyncIterable } from "../types.js";
import { AsyncEqualitySet, EqualitySet } from "./types.js";
export interface EqualitySet<T> extends Iterable<T> {
readonly size: number;
add(value: T): boolean;
addAll(values: Iterable<T>): number;
contains(value: T): boolean;
remove(value: T): boolean;
clear(): void;
values(): IterableIterator<T>;
}
class NativeEqualitySet<T> implements EqualitySet<T> {
export class NativeEqualitySet<T> implements EqualitySet<T> {
readonly #set = new Set<T>();
get size() {
@@ -57,12 +49,12 @@ class NativeEqualitySet<T> implements EqualitySet<T> {
}
}
class CustomEqualitySet<T> implements EqualitySet<T> {
export class CustomEqualitySet<T> implements EqualitySet<T> {
readonly #list: T[] = [];
readonly #equater: EqualityComparison<T>;
readonly #equater: EqualityComparer<T>;
constructor(equater: EqualityComparison<T>) {
this.#equater = equater;
constructor(equater: EqualityComparisonOrComparer<T>) {
this.#equater = asEqualityComparer(equater);
}
get size() {
@@ -93,7 +85,7 @@ class CustomEqualitySet<T> implements EqualitySet<T> {
contains(value: T) {
for (const val of this.#list) {
if (this.#equater(value, val)) {
if (this.#equater.equals(value, val)) {
return true;
}
}
@@ -105,7 +97,7 @@ class CustomEqualitySet<T> implements EqualitySet<T> {
const length = this.#list.length;
for (let i = 0; i < length; i++) {
if (this.#equater(value, this.#list[i])) {
if (this.#equater.equals(value, this.#list[i])) {
this.#list.splice(i, 1);
return true;
}
@@ -127,21 +119,7 @@ class CustomEqualitySet<T> implements EqualitySet<T> {
}
}
export function createEqualitySet<T>(equater?: EqualityComparison<T>): EqualitySet<T> {
return equater ? new CustomEqualitySet(equater) : new NativeEqualitySet<T>();
}
export interface AsyncEqualitySet<T> extends Iterable<T> {
readonly size: number;
add(value: T): Promise<boolean>;
addAll(values: MaybeAsyncIterable<T>): Promise<number>;
contains(value: T): Promise<boolean>;
remove(value: T): Promise<boolean>;
clear(): void;
values(): IterableIterator<T>;
}
class NativeAsyncEqualitySet<T> implements AsyncEqualitySet<T> {
export class NativeAsyncEqualitySet<T> implements AsyncEqualitySet<T> {
readonly #set = new Set<T>();
get size() {
@@ -187,7 +165,7 @@ class NativeAsyncEqualitySet<T> implements AsyncEqualitySet<T> {
}
}
class CustomAsyncEqualitySet<T> implements AsyncEqualitySet<T> {
export class CustomAsyncEqualitySet<T> implements AsyncEqualitySet<T> {
readonly #list: T[] = [];
readonly #equater: MaybeAsyncEqualityComparison<T>;
@@ -256,7 +234,3 @@ class CustomAsyncEqualitySet<T> implements AsyncEqualitySet<T> {
return this.#list[Symbol.iterator]();
}
}
export function createAsyncEqualitySet<T>(equater?: MaybeAsyncEqualityComparison<T>): AsyncEqualitySet<T> {
return equater ? new CustomAsyncEqualitySet(equater) : new NativeAsyncEqualitySet<T>();
}

11
src/equality-set/index.ts Normal file
View File

@@ -0,0 +1,11 @@
import { EqualityComparisonOrComparer, MaybeAsyncEqualityComparison } from "../equality-comparer/types.js";
import { CustomAsyncEqualitySet, CustomEqualitySet, NativeAsyncEqualitySet, NativeEqualitySet } from "./impl.js";
import { AsyncEqualitySet, EqualitySet } from "./types.js";
export function createEqualitySet<T>(equater?: EqualityComparisonOrComparer<T>): EqualitySet<T> {
return equater ? new CustomEqualitySet(equater) : new NativeEqualitySet<T>();
}
export function createAsyncEqualitySet<T>(equater?: MaybeAsyncEqualityComparison<T>): AsyncEqualitySet<T> {
return equater ? new CustomAsyncEqualitySet(equater) : new NativeAsyncEqualitySet<T>();
}

21
src/equality-set/types.ts Normal file
View File

@@ -0,0 +1,21 @@
import { MaybeAsyncIterable } from "../types.js";
export interface EqualitySet<T> extends Iterable<T> {
readonly size: number;
add(value: T): boolean;
addAll(values: Iterable<T>): number;
contains(value: T): boolean;
remove(value: T): boolean;
clear(): void;
values(): IterableIterator<T>;
}
export interface AsyncEqualitySet<T> extends Iterable<T> {
readonly size: number;
add(value: T): Promise<boolean>;
addAll(values: MaybeAsyncIterable<T>): Promise<number>;
contains(value: T): Promise<boolean>;
remove(value: T): Promise<boolean>;
clear(): void;
values(): IterableIterator<T>;
}

View File

@@ -15,5 +15,9 @@ export * as Comparers from "./comparer/sync.js";
export { BaseAsyncComparer } from "./comparer/async.js";
export * as AsyncComparers from "./comparer/async.js";
export * from "./comparer/types.js";
export * as EqualityComparers from "./equality-comparer/index.js";
export * as EqualityComparers from "./equality-comparer/sync.js";
export * from "./equality-comparer/types.js";
export * as EqualityMaps from "./equality-map/index.js";
export * from "./equality-map/types.js";
export * as EqualitySets from "./equality-set/index.js";
export * from "./equality-set/types.js";

View File

@@ -1,6 +1,6 @@
import { BitArray } from "../bitarray/index.js";
import { asArray } from "../utils.js";
import { AsyncRandomOptions, ElementPredicate, ElementWeight, RandomGenerator, RandomOptions } from "./types.js";
import { AsyncRandomOptions, ElementPredicate, ElementWeight, RandomElement, RandomGenerator, RandomOptions } from "./types.js";
export const alwaysTrue: ElementPredicate = () => true;
export const weightOfOne: ElementWeight = () => 1.0;
@@ -45,9 +45,10 @@ function withDefaultOptions<T>(options: RandomOptions<T> | AsyncRandomOptions<T>
};
}
function _getRandomElement<T>(sequence: Iterable<T>, options: Required<RandomOptions<T>>) {
function _getRandomElement<T>(sequence: Iterable<T>, options: Required<RandomOptions<T>>): RandomElement<T> {
const { predicate, weight, random } = options;
let found = false;
let result: T | undefined = undefined;
let resultIndex = -1;
let index = 0;
@@ -66,22 +67,24 @@ function _getRandomElement<T>(sequence: Iterable<T>, options: Required<RandomOpt
weightAcc += w;
if (random() * weightAcc < w) {
found = true;
result = element;
resultIndex = currentIndex;
}
}
}
return { element: result, index: resultIndex };
return { found, element: result, index: resultIndex } as RandomElement<T>;
}
export function getRandomElement<T>(sequence: Iterable<T>, options?: RandomOptions<T>) {
return _getRandomElement(sequence, withDefaultOptions(options));
}
async function _getRandomElementAsync<T>(sequence: AsyncIterable<T>, options: Required<AsyncRandomOptions<T>>) {
async function _getRandomElementAsync<T>(sequence: AsyncIterable<T>, options: Required<AsyncRandomOptions<T>>): Promise<RandomElement<T>> {
const { predicate, weight, random } = options;
let found = false;
let result: T | undefined = undefined;
let resultIndex = -1;
let index = 0;
@@ -100,13 +103,14 @@ async function _getRandomElementAsync<T>(sequence: AsyncIterable<T>, options: Re
weightAcc += w;
if (random() * weightAcc < w) {
found = true;
result = element;
resultIndex = currentIndex;
}
}
}
return { element: result, index: resultIndex };
return { found, element: result, index: resultIndex } as RandomElement<T>;
}
export async function getRandomElementAsync<T>(sequence: AsyncIterable<T>, options?: AsyncRandomOptions<T>) {

View File

@@ -4,7 +4,7 @@ export type ElementPredicate<T = any> = (index: number, obj: T) => boolean;
export type ElementWeight<T = any> = (index: number, obj: T) => number;
export type RandomGenerator = () => number;
export interface RandomOptions<T = any> {
export type RandomOptions<T = any> = {
predicate?: ElementPredicate<T>;
weight?: ElementWeight<T>;
random?: RandomGenerator;
@@ -13,8 +13,20 @@ export interface RandomOptions<T = any> {
export type MaybeAsyncElementPredicate<T = any> = MaybeAsyncFunction<ElementPredicate<T>>;
export type MaybeAsyncElementWeight<T = any> = MaybeAsyncFunction<ElementWeight<T>>;
export interface AsyncRandomOptions<T = any> {
export type AsyncRandomOptions<T = any> = {
predicate?: MaybeAsyncElementPredicate<T>;
weight?: MaybeAsyncElementWeight<T>;
random?: RandomGenerator;
};
type RandomElementFound<T> = {
found: true;
element: T;
index: number;
};
type RandomElementNotFound = {
found: false;
element: undefined;
index: -1;
};
export type RandomElement<T> = RandomElementFound<T> | RandomElementNotFound;

View File

@@ -3,10 +3,10 @@ import { AsyncSequence } from "../async/types.js";
import { Collector } from "../collector/types.js";
import { asComparer, combineNullableComparers, createComparerUsing, defaultComparer } from "../comparer/sync.js";
import { ComparisonOrComparer, Comparer } from "../comparer/types.js";
import { strictEquals } from "../equality-comparer/index.js";
import { strictEquals } from "../equality-comparer/sync.js";
import { EqualityComparison } from "../equality-comparer/types.js";
import { createEqualityMap } from "../equality-map.js";
import { createEqualitySet } from "../equality-set.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";

View File

@@ -9,7 +9,7 @@ export function wrap<T = any>(iterable: Iterable<T>): Sequence<T> {
}
if (Array.isArray(iterable)) {
return array(iterable);
return array<T>(iterable);
}
if (iterable instanceof Set) {
@@ -20,7 +20,7 @@ export function wrap<T = any>(iterable: Iterable<T>): Sequence<T> {
return map(iterable) as unknown as Sequence<T>;
}
return sequence(iterable);
return sequence<T>(iterable);
}
export function sequence<T = any>(iterable: Iterable<T>): Sequence<T> {
@@ -86,9 +86,9 @@ export function generator<T>(generator: () => Iterable<T>): Sequence<T> {
return new GeneratorSequence(generator);
}
export function range(max: number): Sequence<number>
export function range(min: number, max: number): Sequence<number>
export function range(min: number, max: number, step: number): Sequence<number>
export function range(max: number): Sequence<number>;
export function range(min: number, max: number): Sequence<number>;
export function range(min: number, max: number, step: number): Sequence<number>;
export function range(a: number, b?: number, c?: number): Sequence<number> {
if (b === undefined) {
b = a;
@@ -102,9 +102,9 @@ export function range(a: number, b?: number, c?: number): Sequence<number> {
return new RangeSequence(a, b, c);
}
export function bigintRange(max: bigint): Sequence<bigint>
export function bigintRange(min: bigint, max: bigint): Sequence<bigint>
export function bigintRange(min: bigint, max: bigint, step: bigint): Sequence<bigint>
export function bigintRange(max: bigint): Sequence<bigint>;
export function bigintRange(min: bigint, max: bigint): Sequence<bigint>;
export function bigintRange(min: bigint, max: bigint, step: bigint): Sequence<bigint>;
export function bigintRange(a: bigint, b?: bigint, c?: bigint): Sequence<bigint> {
if (b === undefined) {
b = a;