groupBy
Groups items in an array based on a key returned by a callback.
1/**
2 * Groups items in an array based on a key returned by a callback.
3 *
4 * @param arr - The array to group.
5 * @param fn - A function that returns the key for grouping each item.
6 * @returns An object where each key maps to an array of grouped items.
7 */
8export function groupBy<T, K extends string | number>(
9 arr: T[],
10 fn: (item: T) => K
11): Record<K, T[]> {
12 return arr.reduce((acc, item) => {
13 const key = fn(item);
14 (acc[key] ||= []).push(item);
15 return acc;
16 }, {} as Record<K, T[]>);
17}
Flexible key selection
Allows grouping by any derived key (e.g.
user.id
,item.category
,str.length
), enabling a wide range of grouping logic.Single-pass efficiency
Operates in a single
reduce
pass, giving itO(n)
time complexity, which is optimal for this type of transformation.Compact and immutable
Returns a new grouped object without modifying the original array.
Type-safe with generics
Leverages TypeScript’s generics for type inference of the key and grouped values, making it safer in large codebases.
Clean syntax using logical assignment
(acc[key] ||= [])
makes the grouping concise and readable without explicit checks.
Tests | Examples
1test('groupBy - string length', () => {
2 const data = ['apple', 'banana', 'cherry'];
3 expect(groupBy(data, fruit => fruit.length)).toEqual({
4 5: ['apple'],
5 6: ['banana', 'cherry'],
6 });
7});
8
9test('groupBy - objects by field', () => {
10 const users = [
11 { name: 'Alice', role: 'admin' },
12 { name: 'Bob', role: 'user' },
13 { name: 'Eve', role: 'admin' },
14 ];
15 expect(groupBy(users, user => user.role)).toEqual({
16 admin: [
17 { name: 'Alice', role: 'admin' },
18 { name: 'Eve', role: 'admin' },
19 ],
20 user: [
21 { name: 'Bob', role: 'user' },
22 ],
23 });
24});
25
26test('groupBy - empty array', () => {
27 expect(groupBy([], x => x)).toEqual({});
28});
Common Use Cases
UI grouping (e.g. lists, dropdowns, tables)
Grouping items by status, category, tag, author, etc., for rendering in sections or filters.
Data analysis and aggregation
Binning raw data by metric or dimension (e.g., count by year, events per user, tasks per project).
Pre-processing for charts/visualizations
Organizing datasets into categories or series before rendering bar/line/pie charts.
Log/event processing
Bucket events by date, severity, or type for further processing or alerting.