countBy
EditCounts array values by a derived property key.
export type CountByKeySelector<Value, Key extends PropertyKey> = ( this: void, value: Value, index: number) => Key;
/** * Counts are optional because a selector's return type describes every key it * may produce, not a guarantee that every possible key occurs in the input. */export type CountByResult<Key extends PropertyKey> = Partial<Record<Key, number>>;
/** Counts values by a derived property key. */export const countBy = <Value, Key extends PropertyKey>( array: readonly Value[], getKey: CountByKeySelector<Value, Key>): CountByResult<Key> => { const result = Object.create(null) as CountByResult<Key>; for (let index = 0; index < array.length; index += 1) { if (!Object.hasOwn(array, index)) continue; const value = array[index] as Value; const key = getKey(value, index); const count = Reflect.get(result, key) as number | undefined; Reflect.set(result, key, (count ?? 0) + 1); } return result;};Download
Section titled “Download”wget -O src/lib/countBy.ts https://raw.githubusercontent.com/jrTilak/lazykit/HEAD/registry/functions/countBy.tstemp_dir="$(mktemp -d)" && bunx degit jrTilak/lazykit/registry/functions "$temp_dir" && mv "$temp_dir/countBy.ts" src/lib/countBy.ts && rm -r "$temp_dir"Examples
Section titled “Examples”import { countBy } from "./countBy";
const totals = countBy( ["api", "web", "api"] as const, (value) => value);// { api: 2, web: 1 }
const apiCount = totals.api ?? 0;// 2array(readonly T[]) — Values to count. Empty slots are skipped.getKey(CountByKeySelector<T, Key>) — Selects a bucket and is invoked without a receiver.- Returns
Partial<Record<Key, number>>with a null prototype. A count isundefinedwhen that key did not occur.