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 }