groupByToMap
Groups items in a Map based on a key returned by a callback.
1/**
2 * Groups items in a Map based on a key returned by a callback.
3 *
4 * @param arr - Array of items to group.
5 * @param fn - Function that returns a grouping key for each item.
6 * @returns A Map where each key maps to an array of grouped items.
7 */
8export function groupByToMap<T, K>(arr: T[], fn: (item: T) => K): Map<K, T[]> {
9 const result = new Map<K, T[]>();
10 for (const item of arr) {
11 const key = fn(item);
12 if (!result.has(key)) {
13 result.set(key, []);
14 }
15 result.get(key)!.push(item);
16 }
17 return result;
18}
Preserves key types
Unlike
groupBy
, which uses object keys (restricted tostring | number
), this version supports any type as a key — including objects, symbols, dates, tuples, etc., thanks toMap
.Order-preserving
Map
maintains insertion order of keys, which makes it suitable for situations where predictable iteration order is important.Safe against prototype pollution
Since
Map
doesn't inherit fromObject.prototype
, there's no risk of conflicts with inherited keys like__proto__
,constructor
, etc.Type-safe and clean API
Leverages
Map<K, T[]>
for more flexible and expressive typing, especially useful in strongly typed environments like TypeScript.
Tests | Examples
1test('groupByToMap - basic grouping', () => {
2 const words = ['cat', 'car', 'dog', 'duck'];
3 const grouped = groupByToMap(words, word => word[0]);
4 expect(grouped.get('c')).toEqual(['cat', 'car']);
5 expect(grouped.get('d')).toEqual(['dog', 'duck']);
6});
7
8test('groupByToMap - complex keys', () => {
9 const keyA = Symbol('A');
10 const keyB = Symbol('B');
11 const items = [{ t: keyA }, { t: keyB }, { t: keyA }];
12 const grouped = groupByToMap(items, item => item.t);
13
14 expect(grouped.get(keyA)).toEqual([{ t: keyA }, { t: keyA }]);
15 expect(grouped.get(keyB)).toEqual([{ t: keyB }]);
16});
17
18test('groupByToMap - empty input', () => {
19 const result = groupByToMap([], () => 'x');
20 expect(result.size).toBe(0);
21});
Common Use Cases
Indexing by complex keys
Group items by objects, arrays, or other non-primitive identifiers (e.g.,
[userId, date]
, or even entire object snapshots).Cache or memoization scenarios
When using grouped data as part of a cache where keys need to be reliable references.
Preserving original group order
When it's important to retain the order in which groups were encountered (e.g., for UI rendering).
Building lookup tables
Construct fast-access
Map
-based groupings for downstream operations like filtering, sorting, or aggregation.Safer than plain objects in untrusted environments
Especially relevant in serverless environments or public APIs where object pollution could be an attack vector.