thi-ng/umbrella

View on GitHub
packages/transducers/src/norm-frequencies-auto.ts

Summary

Maintainability
A
0 mins
Test Coverage
import type { Fn } from "@thi.ng/api";
import type { Reducer } from "./api.js";
import { frequencies } from "./frequencies.js";
import { $$reduce } from "./reduce.js";

/**
 * Similar to {@link normFrequencies}, but automatically computes normalization
 * basis instead of requiring it ahead of time as argument.
 *
 * @example
 * ```ts
 * import { normFrequenciesAuto } from "@thi.ng/transducers";
 *
 * const items = [1, 2, 3, 1, 1, 4, 2, 5, 1, 2];
 *
 * normFrequenciesAuto(items)
 * // Map(5) { 1 => 0.4, 2 => 0.3, 3 => 0.1, 4 => 0.1, 5 => 0.1 }
 *
 * // frequencies by 1st letter
 * normFrequenciesAuto(x => x[0], ["alice", "abba", "bob", "charlie"])
 * // Map(3) { 'a' => 0.5, 'b' => 0.25, 'c' => 0.25 }
 * ```
 */
export function normFrequenciesAuto<A>(): Reducer<A, Map<A, number>>;
export function normFrequenciesAuto<A>(src: Iterable<A>): Map<A, number>;
export function normFrequenciesAuto<A, B>(
    key: Fn<A, B>
): Reducer<A, Map<B, number>>;
export function normFrequenciesAuto<A, B>(
    key: Fn<A, B>,
    src: Iterable<A>
): Map<B, number>;
export function normFrequenciesAuto<A, B>(...args: any[]): any {
    const res = $$reduce(normFrequenciesAuto, args);
    if (res !== undefined) return res;

    const [init, complete, reduce] = frequencies<B>(...(<[]>args));
    let norm = 0;
    return <Reducer<A, Map<B, number>>>[
        init,
        (acc) => {
            acc = complete(acc);
            for (let p of acc) {
                acc.set(p[0], p[1] / norm);
            }
            return acc;
        },
        (acc: Map<any, number>, x: any) => (norm++, reduce(acc, x)),
    ];
}