groupByMultiToMap
Groups items into a Map based on one or more keys returned by a callback. Each item can be placed into multiple groups.
1/**
2 * Groups items into a Map based on one or more keys returned by a callback.
3 * Each item can be placed into multiple groups.
4 *
5 * @param arr - Array of items to group.
6 * @param fn - Function that returns an array of grouping keys for each item.
7 * @returns A Map where each key maps to an array of items.
8 */
9export function groupByMultiToMap<T, K>(arr: T[], fn: (item: T) => K[]): Map<K, T[]> {
10 const result = new Map<K, T[]>();
11
12 for (const item of arr) {
13 const keys = fn(item);
14 for (const key of keys) {
15 if (!result.has(key)) {
16 result.set(key, []);
17 }
18 result.get(key)!.push(item);
19 }
20 }
21
22 return result;
23}
Supports multiple groupings per item
Unlike standard grouping functions, this utility allows each item to belong to multiple groups, enabling advanced categorization (e.g., tagging systems, faceted filters).
Key type flexibility via
Map
Allows grouping by any key type - including objects, arrays, symbols, or custom types - not limited to strings or numbers as in plain objects.
Insertion order preserved
Map
ensures consistent ordering of keys based on the sequence of first appearance, which is helpful for rendering or display purposes.Efficient lookup and storage
Uses
Map
for optimized key access and to avoid prototype chain issues inherent in plain object usage.Type-safe and expressive
Strong TypeScript support makes the utility reliable in typed projects, with explicit handling of key arrays per item.
Tests | Examples
1test('groupByMultiToMap - basic usage', () => {
2 const animals = [
3 { name: 'dog', tags: ['mammal', 'pet'] },
4 { name: 'cat', tags: ['mammal', 'pet'] },
5 { name: 'crocodile', tags: ['reptile', 'wild'] }
6 ];
7
8 const grouped = groupByMultiToMap(animals, animal => animal.tags);
9
10 expect(grouped.get('mammal')).toEqual([
11 { name: 'dog', tags: ['mammal', 'pet'] },
12 { name: 'cat', tags: ['mammal', 'pet'] }
13 ]);
14
15 expect(grouped.get('pet')).toEqual([
16 { name: 'dog', tags: ['mammal', 'pet'] },
17 { name: 'cat', tags: ['mammal', 'pet'] }
18 ]);
19
20 expect(grouped.get('reptile')).toEqual([
21 { name: 'crocodile', tags: ['reptile', 'wild'] }
22 ]);
23
24 expect(grouped.get('wild')).toEqual([
25 { name: 'crocodile', tags: ['reptile', 'wild'] }
26 ]);
27});
28
29test('groupByMultiToMap - empty array', () => {
30 const grouped = groupByMultiToMap([], () => ['x']);
31 expect(grouped.size).toBe(0);
32});
33
34test('groupByMultiToMap - empty keys array', () => {
35 const grouped = groupByMultiToMap(['a', 'b'], () => []);
36 expect(grouped.size).toBe(0);
37});
Common Use Cases
Tag-based grouping
Items associated with multiple tags (e.g., blog posts, documents, products) can be grouped by all associated tags simultaneously.
Feature faceting in search UIs
Useful for faceted filters, where a product might fall under several filter categories like color, size, and brand.
Permission roles and access mapping
Users or resources may map to multiple roles or scopes, and this utility helps create role-based collections for further processing.
Reverse lookup scenarios
Build maps where each key is linked to all items that reference it, such as dependencies, references, or relations.
Data visualization and analytics
When preparing grouped datasets for charts or aggregations that must account for overlapping group membership.