Skip to main content

Grouping a Collection

Grouping means sorting elements into buckets. You choose a key for every element, and all elements with the same key land in the same bucket.

The key is computed by a small function that takes one element and returns its key. For example, the first letter of a word.

Map.groupBy() does the whole job. Give it an array and a key function and it returns a Map from key to an array of the elements with that key.

A Map keeps its keys in the order they were first added, so the printed output always looks the same. console.log() prints a Map like this: Map(1) { 'a' => [ 1 ] } — the number of keys first, then every key and its value. When one line would get too long, the keys are printed one per line instead.

There is also Object.groupBy(), which returns a plain object instead of a Map. The examples here use Map.groupBy(), because a Map accepts keys of any type and prints how many keys it has.


Group By Key

The simplest grouping keeps the elements as they are and only decides which bucket each one goes to.

Pass the array and a key function to Map.groupBy(). The result is a Map from key to the array of elements with that key. The elements inside a group keep the order they had in the input.

Sometimes you want to change the elements while grouping, for example store them in upper case. Map.groupBy() has no parameter for that. Write the loop yourself: compute the key, compute the new value, and push the new value into the group. groups.get(key) ?? [] gives the group that is already there, or a new empty array for a key you have not seen yet.

Group words by first letter

The key function takes the first letter of the word with w[0] and makes it upper case with toUpperCase(). Words that start with the same letter end up in the same array. The keys print in the order they were first seen: 'O', 'T', 'F'.

Prompt
Write a TypeScript program that groups the words one, two, three, four, five with Map.groupBy(), using the upper-case first letter as the key. Print the resulting Map.
Output: TypeScript file and captured output
Group words by first letter

Group and change the values

The key is the lower-case first letter. The stored value is the whole word in upper case. A for...of loop does both steps and pushes the new value into the array from groups.get(key) ?? [].

Prompt
Write a TypeScript program that groups the words one, two, three, four, five by their lower-case first letter, but stores each word in its group in upper case. Build the Map with a for...of loop and groups.get(key) ?? [], then print it.
Output: TypeScript file and captured output
Group and change the values

Count Each Group

Often you do not need the elements of each group, only how many there are.

There is no eachCount(). Use a Map<string, number> instead. Reading a key that is not in the Map gives undefined, not 0, so write (counts.get(key) ?? 0) + 1. The ?? operator supplies the starting value 0 for the first element of a group.

Count words per first letter

Every word adds 1 to the count of its first letter. The Map ends up with one number per letter: 'o' => 1, 't' => 2 and 'f' => 2.

Prompt
Write a TypeScript program that counts how many of the words one, two, three, four, five start with each letter. Use a Map from the first letter to a number and (counts.get(key) ?? 0) + 1 to increase the count. Print the Map.
Output: TypeScript file and captured output
Count words per first letter

Fold and Reduce per Group

Folding a group means combining its elements into one value, step by step. A running total is the classic example: start at 0 and add each element.

reduce() does exactly this. It carries one value — the accumulator — through the whole array. Here the accumulator is a Map that holds the running value of every group. For each element you compute its key and update the value stored under that key.

When the running value has a starting value, such as 0 for a sum, ?? 0 supplies it for a key that is not there yet. When the first element itself must start the value, compare the result of get() with undefined to tell the two cases apart.

Sum each group

Each number is put in the group "even" or "odd" and added to that group's sum with acc.set(key, (acc.get(key) ?? 0) + n). A new key starts at 0, so no special case is needed. The first number is 3, so 'odd' is the first key of the Map.

Prompt
Write a TypeScript program that takes the numbers 3, 4, 5, 6, 7, 8 and puts each one in the group "even" or "odd". Use reduce() with a Map as the accumulator to keep a running sum per group, then print the Map.
Output: TypeScript file and captured output
Sum each group

Build a string per group

The first number of a group starts the string. Every later number is joined with "+". acc.get(key) gives undefined for a group that is still empty, and that tells the two cases apart. String(n) turns a number into text.

Prompt
Write a TypeScript program that takes the numbers 3, 4, 5, 6, 7, 8 and puts each one in the group "even" or "odd". Use reduce() with a Map as the accumulator to build a string per group, where the first number starts the string and every later number is added with a "+" in front, giving text like 3+5+7. Print the Map.
Output: TypeScript file and captured output
Build a string per group