countBy
Counts the number of occurrences of items in an array based on a key-generating function.
1/**
2 * Counts the number of occurrences of items in an array based on a key-generating function.
3 *
4 * @param arr - The input array of values.
5 * @param fn - A callback that returns a key for each element.
6 * @returns An object with keys and their associated counts.
7 */
8export function countBy<T>(
9 arr: T[],
10 fn: (item: T) => string | number
11): Record<string, number> {
12 return arr.reduce((acc, item) => {
13 const key = String(fn(item));
14 acc[key] = (acc[key] || 0) + 1;
15 return acc;
16 }, {} as Record<string, number>);
17}
Flexible key extraction
Supports a custom
fn
that determines how items are grouped and counted, enabling counting by any derived property (length, type, category, etc.).Handles any data type
Can process arrays of strings, numbers, objects, or mixed types, as long as a valid key can be extracted.
Efficient single-pass
Uses a single
reduce
traversal to compute all counts, optimizing performance for large datasets.String-key normalization
Ensures compatibility by converting all keys to strings, preventing object key collisions or unexpected behavior.
Clear output structure
Returns a plain object mapping keys to count values, ideal for use in reporting, analytics, or visualization.
Tests | Examples
1test('countBy - count by string length', () => {
2 expect(countBy(['one', 'two', 'three'], x => x.length)).toEqual({ '3': 2, '5': 1 });
3});
4
5test('countBy - count by first letter', () => {
6 expect(countBy(['apple', 'apricot', 'banana', 'blueberry'], x => x[0]))
7 .toEqual({ a: 2, b: 2 });
8});
9
10test('countBy - numbers grouped by modulo', () => {
11 expect(countBy([1, 2, 3, 4, 5, 6], x => x % 2 === 0 ? 'even' : 'odd'))
12 .toEqual({ odd: 3, even: 3 });
13});
14
15test('countBy - empty array', () => {
16 expect(countBy([], x => x)).toEqual({});
17});
Common Use Cases
Analytics and metrics
Counting categories, frequencies, or types within a dataset (e.g., number of users per role, product sales by category).
Text and log processing
Tally word lengths, first letters, file extensions, or log severity levels.
Data grouping previews
Generate counts to preview how many items would fall into each group before applying more expensive transformations.
Survey result summaries
Count answer frequencies from a set of responses.
Dashboard aggregates
Build quick count-based summaries in UI dashboards or tables.