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

Преобразование коллекции

Преобразование берёт коллекцию, например массив или Map, и строит из неё новую коллекцию. Исходная коллекция не изменяется.

Массивы в TypeScript уже содержат большинство таких операций в виде методов: map, filter, flat, flatMap и join. Вы вызываете их на массиве и получаете новое значение, поэтому цикл не нужен. У некоторых операций, например у zip, встроенного метода нет — для них один раз пишут маленькую вспомогательную функцию и переиспользуют её.

Вспомогательная функция может быть обобщённой. Обобщённая функция работает с любым типом элементов: вы один раз пишете function zip<A, B>(first: A[], second: B[]): [A, B][] и используете её и для чисел, и для строк, и для объектов. Параметры типа A и B подставляет компилятор в месте вызова.


Map

Операция map применяет одну и ту же функцию к каждому элементу и собирает ответы в новый массив той же длины. Например, она может превратить [ 1, 2, 3 ] в [ 3, 6, 9 ].

У массивов есть встроенный метод map. Вы передаёте ему функцию, и он возвращает новый массив. Тип результата следует за функцией: если функция возвращает string, вы получаете string[].

Не путайте это с классом Map, который хранит пары ключ — значение. Здесь «map» означает «применить функцию к каждому элементу».

Отображение каждого элемента

numbers.map(x => x * 3) вызывает функцию для каждого элемента и возвращает новый массив. Исходный массив numbers тоже выводится, чтобы показать, что он по-прежнему содержит [ 1, 2, 3 ].

Prompt
Напишите программу, которая начинается с массива 1, 2, 3 и использует встроенный метод map, чтобы умножить каждое число на 3. Выведите исходный массив и новый массив.
Вывод: программа на TypeScript и захваченный вывод
Map every element

Отображение с индексом

Иногда важна и позиция элемента. Функция обратного вызова map получает индекс вторым аргументом, поэтому можно использовать оба значения. Здесь каждое значение умножается на собственный индекс, и первый элемент становится равен 0.

Prompt
Напишите программу, которая отображает массив 1, 2, 3 в новый массив, где каждый элемент — это значение, умноженное на собственный индекс, используя аргумент индекса функции обратного вызова map. Выведите результат.
Вывод: программа на TypeScript и захваченный вывод
Map with the index

Пропуск части результатов

Иногда часть результатов нужно отбросить. Пусть функция обратного вызова возвращает undefined для таких элементов, а затем уберите их с помощью filter. Вспомогательная функция isDefined — это защитник типа: её тип возврата value is T сообщает компилятору, что каждое значение, прошедшее фильтр, больше не является undefined. Это сужает тип результата с (number | undefined)[] до number[].

Prompt
Отобразите массив 1, 2, 3 так, чтобы число 2 стало undefined, а остальные были умножены на 3. Затем уберите значения undefined с помощью filter и защитника типа с именем isDefined, чтобы результат имел тип number[]. Выведите массив до и после фильтрации.
Вывод: программа на TypeScript и захваченный вывод
Skip some results

Преобразование ключей

Чтобы изменить ключи Map, разверните его в массив пар [key, value] с помощью [...numbersMap], отобразите каждую пару в новую пару и передайте результат в new Map(...). Здесь toUpperCase() изменяет каждый ключ. Map хранит записи в порядке вставки, поэтому вывод всегда идёт в одном и том же порядке.

Prompt
Начните с Map из «key1» в 1 и «key2» в 2. Постройте новый Map с теми же значениями, но со всеми ключами в верхнем регистре. Выведите старый Map и новый.
Вывод: программа на TypeScript и захваченный вывод
Transform the keys

Преобразование значений

Чтобы изменить значения, сделайте то же самое, но сохраните ключ и вычислите новое значение. Здесь каждое значение увеличивается на длину своего ключа: 1 + "key1".length равно 5.

Prompt
Начните с Map из «key1» в 1 и «key2» в 2. Постройте новый Map с теми же ключами, где каждое значение — это старое значение плюс длина его ключа. Выведите новый Map.
Вывод: программа на TypeScript и захваченный вывод
Transform the values

Zip

Zip берёт два массива и соединяет их элементы по позициям: первый с первым, второй со вторым и так далее. В результате получается столько пар, сколько элементов в более коротком массиве.

Встроенного метода zip нет, поэтому обычное решение — маленькая вспомогательная функция. Пара записывается как кортежный тип [A, B]: массив фиксированной длины, где у каждой позиции свой тип. Найдите меньшую длину с помощью Math.min и пройдите циклом по индексу, строя пары.

Соединение двух массивов

Обобщённая вспомогательная функция zip возвращает здесь [string, string][]: массив кортежей из двух элементов. Цикл идёт до меньшей длины и строит по одному кортежу на индекс. При выводе каждая пара показана как отдельный маленький массив.

Prompt
Напишите обобщённую вспомогательную функцию zip, которая соединяет элементы двух массивов по позициям и останавливается на более коротком массиве, возвращая массив кортежей [A, B]. Примените её к рыжий, коричневый, серый и лис, медведь, волк и выведите пары.
Вывод: программа на TypeScript и захваченный вывод
Zip two arrays

Соединение с преобразованием

Сами пары нужны не всегда. Здесь цикл сразу использует оба элемента, чтобы построить предложение. animals[i][0] — это первая буква, переведённая в верхний регистр с помощью toUpperCase(), а animals[i].slice(1) — остаток слова. Предложение собирается с помощью шаблонной строки.

Prompt
Пройдите по массивам рыжий, коричневый, серый и лис, медведь, волк вместе по индексу и выведите для каждой позиции предложение вида «Лис — рыжий», где первая буква названия животного стоит в верхнем регистре.
Вывод: программа на TypeScript и захваченный вывод
Zip with a transformation

Разделение массива пар

Unzip — обратная операция: один массив пар превращается в два массива. Цикл for...of деструктурирует каждый кортеж в word и value и добавляет части в два отдельных массива.

Prompt
Начните с массива кортежей [string, number]: one с 1, two с 2, three с 3. Разделите его на массив слов и массив чисел, затем выведите каждый массив на отдельной строке.
Вывод: программа на TypeScript и захваченный вывод
Unzip an array of pairs

Associate

Ассоциирование строит Map из массива. Каждый элемент даёт один ключ и одно значение. Map не может хранить один и тот же ключ дважды, поэтому если два элемента дают одинаковый ключ, побеждает более поздний.

Короткий способ — применить map к каждому элементу, превратив его в кортеж [key, value] и передать полученный массив в new Map(...). Укажите тип возврата функции обратного вызова как [string, number], чтобы компилятор увидел кортеж, а не обычный массив.

Элементы как ключи

Сам элемент становится ключом, а значение вычисляется из него. Здесь слова — это ключи, а их длины — значения, поэтому lengths.get("three") равно 5.

Prompt
Постройте Map из слов one, two, three, где каждое слово является ключом, а его длина — значением. Выведите Map и значение, сохранённое для «three».
Вывод: программа на TypeScript и захваченный вывод
Elements as keys

Элементы как значения

Элемент становится значением, а ключ вычисляется из него. Здесь ключ — это первая буква в верхнем регистре. И two, и three начинаются с T, поэтому three заменяет two, и размер Map равен 2.

Prompt
Постройте Map из слов one, two, three, где ключ — первая буква в верхнем регистре, а значение — само слово. Выведите Map и его размер и обратите внимание, что «three» заменяет «two» под ключом T.
Вывод: программа на TypeScript и захваченный вывод
Elements as values

Вычисление и ключа, и значения

Из элемента можно вычислить и ключ, и значение. Здесь ключ — это первая буква, а значение — длина слова. Снова побеждает более поздняя запись с ключом T, поэтому T хранит 5 — длину слова three.

Prompt
Постройте Map из слов one, two, three, где ключ — первая буква в верхнем регистре, а значение — длина слова. Выведите Map.
Вывод: программа на TypeScript и захваченный вывод
Compute both key and value

Ключ и значение из одного элемента

Иногда один элемент содержит обе части. split(" ") разрезает полное имя по пробелу на массив слов. Фамилия становится ключом, а имя — значением.

Prompt
Начните с полных имён «Alice Adams» и «Brian Brown». Разделите каждое имя по пробелу и постройте Map из фамилии в имя. Выведите Map.
Вывод: программа на TypeScript и захваченный вывод
Key and value from one element

Разглаживание

Разглаживание превращает вложенную коллекцию, например массив массивов, в один обычный массив со всеми элементами по порядку.

У массивов есть для этого два метода. flat() разглаживает один уровень существующего массива массивов. flatMap(f) делает оба шага сразу: отображает каждый элемент в массив, а затем разглаживает результаты, что удобно, когда внутренние массивы получаются из самих элементов.

Разглаживание массива массивов

numberSets.flat() копирует элементы каждого вложенного массива в один новый массив. Два вложенных массива по три числа превращаются в один массив из шести элементов.

Prompt
Начните с массива массивов: 1, 2, 3 и 4, 5, 6. С помощью flat() превратите его в один плоский массив, затем выведите массив и его длину.
Вывод: программа на TypeScript и захваченный вывод
Flatten an array of arrays

Разглаживание значений из объектов

Каждый объект Container хранит массив в поле values. flatMap(c => c.values) читает это поле у каждого контейнера и объединяет все массивы в один. Восемь значений из трёх контейнеров оказываются вместе, и они выводятся объединёнными через запятые, чтобы поместиться в одну строку.

Prompt
Определите интерфейс Container с полем values, которое является массивом строк. Создайте три контейнера, содержащие one, two, three; four, five; и six, seven, eight. С помощью flatMap соберите все их значения в один массив, затем выведите, сколько их, и значения, объединённые через «, ».
Вывод: программа на TypeScript и захваченный вывод
Flatten values from objects

Строковое представление

Часто коллекцию нужно показать как читаемый текст, например с запятыми между элементами.

Метод join принимает разделитель и возвращает одну строку. Он сам превращает каждый элемент в текст, поэтому для чисел дополнительный шаг не нужен. У join нет других настроек, кроме разделителя, поэтому дополнения — префикс, постфикс, ограничение или преобразование — делаются вокруг него: с помощью +, slice или map перед объединением.

Объединение с разделителем

words.join(", ") помещает ", " между словами и возвращает одну строку.

Prompt
Объедините слова one, two, three в одну строку с «, » между ними, используя метод join, и выведите строку.
Вывод: программа на TypeScript и захваченный вывод
Join with a separator

Добавление префикса и постфикса

Префикс и постфикс — это просто текст вокруг объединённого результата. Вы добавляете их с помощью +.

Prompt
Объедините слова one, two, three через « | », добавьте префикс «начало: » и постфикс «: конец» и выведите результат.
Вывод: программа на TypeScript и захваченный вывод
Add a prefix and a postfix

Ограничение количества элементов

Для длинного массива вы можете захотеть показать только первые несколько элементов. Возьмите первые 10 с помощью numbers.slice(0, 10) и объедините их — join сам превращает числа в текст. Затем добавьте в конце ", <...>", чтобы показать, что остальные элементы отброшены.

Prompt
Создайте массив с числами от 1 до 100. Объедините только первые 10 из них через «, » и добавьте в конце «, <...>», чтобы показать, что список обрезан. Выведите результат.
Вывод: программа на TypeScript и захваченный вывод
Limit the number of elements

Преобразование каждого элемента перед объединением

Чтобы изменить каждый элемент перед объединением, сначала примените к массиву map, а затем вызовите join на результате. Здесь каждое слово становится "Элемент: " плюс слово в верхнем регистре.

Prompt
Превратите каждое из слов one, two, three в «Элемент: », за которым следует слово в верхнем регистре. Объедините результаты через «, » и выведите строку.
Вывод: программа на TypeScript и захваченный вывод
Transform each element before joining