import { curry } from '@typed/lambda' /** * Group and reduce a list of values. * @param f :: (b -> a -> b) * @param seed :: b * @param by :: (a -> PropertyKey) * @returns { [PropertyKey]: B } */ export const reduceBy = curry( ( f: (acc: B, x: A) => B, seed: B, by: (a: A) => PropertyKey, list: A[], ): { readonly [key: string]: B } => { const length = list.length const newObj: any = {} for (let i = 0; i < length; ++i) { const a = list[i] const key = by(a) const b = f(newObj[key] || seed, a) newObj[key] = b } return newObj }, ) as ReduceByArity4 export interface ReduceByArity4 { ( f: (acc: B, value: A) => B, seed: B, by: (a: A) => PropertyKey | number, list: ReadonlyArray, ): { readonly [key: string]: B } (f: (acc: B, value: A) => B): ReduceByArity3 (f: (acc: B, value: A) => B, seed: B): ReduceByArity2 (f: (acc: B, value: A) => B, seed: B, by: (a: A) => PropertyKey): ReduceByArity1 } export interface ReduceByArity3 { (seed: B, by: (a: A) => PropertyKey | number, list: ReadonlyArray): { readonly [key: string]: B } (seed: B, by: (a: A) => PropertyKey | number): ReduceByArity1 (seed: B): ReduceByArity2 } export interface ReduceByArity2 { (by: (a: A) => PropertyKey | number, list: ReadonlyArray): { readonly [key: string]: B } (by: (a: A) => PropertyKey | number): ReduceByArity1 } export type ReduceByArity1 = (list: ReadonlyArray) => { readonly [key: string]: B }