import { Converter } from "../types.js"; import { Collector } from "./types.js"; export class SimpleCollector implements Collector { readonly #initialize: () => TAccumulator; readonly #accumulate: (accumulator: TAccumulator, element: TElement) => void; readonly #finalize: (accumulator: TAccumulator) => TResult; constructor(initialize: () => TAccumulator, accumulate: (accumulator: TAccumulator, element: TElement) => void, finalize: (accumulator: TAccumulator) => TResult) { this.#initialize = initialize; this.#accumulate = accumulate; this.#finalize = finalize; } initialize() { return this.#initialize(); } accumulate(accumulator: TAccumulator, element: TElement) { this.#accumulate(accumulator, element); } finalize(accumulator: TAccumulator): TResult { return this.#finalize(accumulator); } } export class ToArrayCollector implements Collector { initialize(): TElement[] { return []; } accumulate(accumulator: TElement[], element: TElement) { accumulator.push(element); } finalize(accumulator: TElement[]) { return accumulator; } } export class ToObjectCollector implements Collector, Record> { readonly #keySelector: Converter; readonly #valueSelector: Converter; constructor(keySelector: Converter, valueSelector: Converter) { this.#keySelector = keySelector; this.#valueSelector = valueSelector; } initialize() { return {} as Record; } accumulate(accumulator: Record, element: TElement) { const key = this.#keySelector(element); const value = this.#valueSelector(element); accumulator[key] = value; } finalize(accumulator: Record) { return accumulator; } } export class ToObjectListCollector implements Collector, Record> { readonly #keySelector: Converter; readonly #valueSelector: Converter; constructor(keySelector: Converter, valueSelector: Converter) { this.#keySelector = keySelector; this.#valueSelector = valueSelector; } initialize() { return {} as Record; } accumulate(accumulator: Record, element: TElement) { const key = this.#keySelector(element); const value = this.#valueSelector(element); const l = accumulator[key]; if (l) { l.push(value); } else { accumulator[key] = [value]; } } finalize(accumulator: Record) { return accumulator; } } export class ToMapCollector implements Collector, Map> { readonly #keySelector: Converter; readonly #valueSelector: Converter; constructor(keySelector: Converter, valueSelector: Converter) { this.#keySelector = keySelector; this.#valueSelector = valueSelector; } initialize() { return new Map(); } accumulate(accumulator: Map, element: TElement) { const key = this.#keySelector(element); const value = this.#valueSelector(element); accumulator.set(key, value); } finalize(accumulator: Map) { return accumulator; } } export class ToMapListCollector implements Collector, Map> { readonly #keySelector: Converter; readonly #valueSelector: Converter; constructor(keySelector: Converter, valueSelector: Converter) { this.#keySelector = keySelector; this.#valueSelector = valueSelector; } initialize() { return new Map(); } accumulate(accumulator: Map, element: TElement) { const key = this.#keySelector(element); const value = this.#valueSelector(element); const l = accumulator.get(key); if (l) { l.push(value); } else { accumulator.set(key, [value]); } } finalize(accumulator: Map) { return accumulator; } } export class ToSetCollector implements Collector, Set> { initialize() { return new Set(); } accumulate(accumulator: Set, element: TElement) { accumulator.add(element); } finalize(accumulator: Set) { return accumulator; } } export class JoinCollector implements Collector { readonly #delimiter: string; readonly #prefix: string; readonly #suffix: string; constructor(delimiter?: string, prefix?: string, suffix?: string) { this.#delimiter = delimiter ?? ""; this.#prefix = prefix ?? ""; this.#suffix = suffix ?? ""; } initialize(): any[] { return []; } accumulate(accumulator: any[], element: string) { accumulator.push(element); } finalize(accumulator: any[]) { return this.#prefix + accumulator.join(this.#delimiter) + this.#suffix; } } export class SumCollector implements Collector { initialize() { return { sum: 0 }; } accumulate(accumulator: { sum: number; }, element: number) { accumulator.sum += element; } finalize(accumulator: { sum: number; }) { return accumulator.sum; } } export class BigIntSumCollector implements Collector { initialize() { return { sum: 0n, }; } accumulate(accumulator: { sum: bigint; }, element: bigint) { accumulator.sum += element; } finalize(accumulator: { sum: bigint; }) { return accumulator.sum; } } export class AverageCollector implements Collector { initialize() { return { count: 0, sum: 0 }; } accumulate(accumulator: { count: number, sum: number; }, element: number) { accumulator.count++; accumulator.sum += element; } finalize(accumulator: { count: number, sum: number; }) { return accumulator.count === 0 ? 0 : accumulator.sum / accumulator.count; } } export class BigIntAverageCollector implements Collector { initialize() { return { count: 0, sum: 0n }; } accumulate(accumulator: { count: number, sum: bigint; }, element: bigint) { accumulator.count++; accumulator.sum += element; } finalize(accumulator: { count: number, sum: bigint; }) { return accumulator.count === 0 ? 0n : accumulator.sum / BigInt(accumulator.count); } }