Перейти к основному содержимому

Группировка коллекции

Группировка — это раскладывание элементов по корзинам. Вы выбираете ключ для каждого элемента, и все элементы с одинаковым ключом попадают в одну корзину.

Ключ вычисляет небольшая функция, которая принимает один элемент и возвращает его ключ. Например, первую букву слова.

Map.groupBy() делает всю работу. Передайте ему массив и функцию ключа, и он вернёт Map, сопоставляющий ключ массиву элементов с этим ключом.

Map хранит ключи в том порядке, в котором они были добавлены впервые, поэтому напечатанный результат всегда выглядит одинаково. console.log() выводит Map так: Map(1) { 'a' => [ 1 ] } — сначала количество ключей, затем каждый ключ и его значение. Если одна строка получилась бы слишком длинной, ключи выводятся по одному на строку.

Есть также Object.groupBy(), который возвращает обычный объект вместо Map. В примерах здесь используется Map.groupBy(), потому что Map принимает ключи любого типа и выводит, сколько у него ключей.


Группировка по ключу

Самая простая группировка оставляет элементы такими, какие они есть, и только решает, в какую корзину попадёт каждый из них.

Передайте массив и функцию ключа в Map.groupBy(). Результат — Map, сопоставляющий ключ массиву элементов с этим ключом. Элементы внутри группы сохраняют тот порядок, который был у них во входных данных.

Иногда нужно изменить элементы во время группировки, например сохранить их в верхнем регистре. У Map.groupBy() нет параметра для этого. Напишите цикл сами: вычислите ключ, вычислите новое значение и добавьте новое значение в группу. groups.get(key) ?? [] даёт группу, которая уже есть, или новый пустой массив для ключа, который вы ещё не встречали.

Группировка слов по первой букве

Функция ключа берёт первую букву слова с помощью w[0] и переводит её в верхний регистр методом toUpperCase(). Слова, начинающиеся с одной и той же буквы, попадают в один массив. Ключи выводятся в том порядке, в котором были впервые встречены: 'O', 'T', 'F'.

Prompt
Напишите программу на TypeScript, которая группирует слова one, two, three, four, five с помощью Map.groupBy(), используя в качестве ключа первую букву в верхнем регистре. Выведите получившийся Map.
Вывод: программа на TypeScript и захваченный вывод
Group words by first letter

Группировка с изменением значений

Ключ — первая буква в нижнем регистре. Сохраняемое значение — всё слово в верхнем регистре. Цикл for...of выполняет оба шага и добавляет новое значение в массив, полученный из groups.get(key) ?? [].

Prompt
Напишите программу на TypeScript, которая группирует слова one, two, three, four, five по их первой букве в нижнем регистре, но сохраняет каждое слово в своей группе в верхнем регистре. Постройте Map с помощью цикла for...of и выражения groups.get(key) ?? [], затем выведите его.
Вывод: программа на TypeScript и захваченный вывод
Group and change the values

Подсчёт элементов каждой группы

Часто вам нужны не сами элементы каждой группы, а только их количество.

Метода eachCount() не существует. Используйте вместо него Map<string, number>. Чтение ключа, которого нет в Map, даёт undefined, а не 0, поэтому пишите (counts.get(key) ?? 0) + 1. Оператор ?? подставляет начальное значение 0 для первого элемента группы.

Подсчёт слов по первой букве

Каждое слово добавляет 1 к счётчику своей первой буквы. В итоге Map содержит по одному числу на букву: 'o' => 1, 't' => 2 и 'f' => 2.

Prompt
Напишите программу на TypeScript, которая считает, сколько слов из one, two, three, four, five начинается с каждой буквы. Используйте Map, сопоставляющий первую букву числу, и выражение (counts.get(key) ?? 0) + 1 для увеличения счётчика. Выведите Map.
Вывод: программа на TypeScript и захваченный вывод
Count words per first letter

Свёртка и редукция по группам

Свернуть группу — значит шаг за шагом объединить её элементы в одно значение. Классический пример — текущая сумма: начать с 0 и прибавлять каждый элемент.

reduce() делает именно это. Он проносит одно значение — аккумулятор — через весь массив. Здесь аккумулятор — это Map, который хранит текущее значение каждой группы. Для каждого элемента вы вычисляете его ключ и обновляете значение, сохранённое под этим ключом.

Когда у текущего значения есть начальное значение, например 0 для суммы, ?? 0 подставляет его для ключа, которого ещё нет. Когда же первый элемент сам должен задать начальное значение, сравните результат get() с undefined, чтобы различить эти два случая.

Сумма каждой группы

Каждое число помещается в группу "even" или "odd" и прибавляется к сумме этой группы выражением acc.set(key, (acc.get(key) ?? 0) + n). Новый ключ начинается с 0, поэтому особый случай не нужен. Первое число — 3, поэтому 'odd' — первый ключ этого Map.

Prompt
Напишите программу на TypeScript, которая берёт числа 3, 4, 5, 6, 7, 8 и помещает каждое из них в группу "even" или "odd". Используйте reduce() с Map в качестве аккумулятора, чтобы хранить текущую сумму для каждой группы, затем выведите Map.
Вывод: программа на TypeScript и захваченный вывод
Sum each group

Построение строки для каждой группы

Первое число группы начинает строку. Каждое следующее число присоединяется через "+". acc.get(key) даёт undefined для группы, которая ещё пуста, и это позволяет различить два случая. String(n) превращает число в текст.

Prompt
Напишите программу на TypeScript, которая берёт числа 3, 4, 5, 6, 7, 8 и помещает каждое из них в группу "even" или "odd". Используйте reduce() с Map в качестве аккумулятора, чтобы построить строку для каждой группы: первое число начинает строку, а каждое следующее добавляется со знаком "+" перед ним, давая текст вида 3+5+7. Выведите Map.
Вывод: программа на TypeScript и захваченный вывод
Build a string per group