[БЕЗ_ЗВУКА] Что же еще можно делать со словарями? Во-первых, можно создавать и указывать конкретный набор пар ключ-значение. Точно так же, как и векторы. Давайте я возьму словарь из строчек в целые числа, назову его m, и с помощью фигурных скобок укажу конкретные пары ключ-значение, которые мне нужны. Например, я захочу для каждого английского названия цифры хранить значение этой цифры. Соответственно, я указываю в еще одних фигурных скобках пару ключ-значение, потом, допустим, еще раз ключ-значение, и, наконец, для тройки ключ-значение. Итак, у меня готов словарь, я его выведу с помощью функции, которую я уже заготовил. PrintMap принимает словарь из строк в целые числа и делает по нему обычный цикл for. Правда, давайте прежде чем я запущу код и выведу этот словарь, я все-таки сделаю эту функцию чуть аккуратнее — перестану копировать здесь очередную пару ключ-значение в переменную item с помощью константной ссылки. Теперь компилятор будет видеть, что здесь константная ссылка на какой-то тип — на пару из ключа и значения. Давайте я выведу этот словарь, вызову функцию PrintMap от словаря m. Скомпилирую код и увижу, что у меня в словаре три пары: one со значением 1, three со значением 3, и two со значением 2. При этом все ключи отсортировались лексикографически, то есть в алфавитном порядке. Поэтому three получилось раньше, чем two. Превосходно! Кстати говоря, этот словарь, у которого мы задали конкретные пары ключ-значение, можно после этого поменять. Например, я могу захотеть удалить тройку — решить, что мне двух цифр достаточно. Как удалить конкретную пару ключ-значение из словаря? На самом деле очень просто — вызвать метод с говорящим названием erase. Этот метод принимает ровно один аргумент — это тот ключ, который мы удаляем. Поскольку все ключи в словаре уникальны, будет совершенно очевидно компилятору, какую именно запись надо удалить. Если мы хотим удалить тройку, пишем three. И после этого смотрим, каким у нас будет словарь. Вот этот вывод мы закомментируем, компилируем код и видим, что теперь в словаре две пары ключ-значение: one со значением 1 и two со значением 2, то есть мы успешно удалили тройку из этого словаря. Прекрасно! Что еще, какие задачи можно решать с помощью словарей? Например, представьте, что у вас есть набор строк в виде вектора, каких-то слов. Давайте так назовем: слова. И здесь есть какие-то строки, возможно, повторяющиеся. Например, сначала one, потом two, а потом снова one. И мы хотим посчитать, сколько раз встречается в этом наборе каждое слово. Конечно, мы для этого можем использовать словарь из строк в целые числа. Для каждого слова будем хранить, сколько раз оно встречается. Назовем его counters. Как нам теперь заполнить этот словарь? Наверное, надо проитерироваться константной ссылкой по всем словам, чтобы лишний раз не копировать в переменную word. И затем нужно обновить значение counters от word. Как мы это должны сделать? Первое, что приходит в голову — это сначала проверить, есть ли такой ключ в словаре. Давайте попробуем. Как проверить, есть ли ключ в словаре? Для этого есть метод count, который возвращает, сколько раз этот ключ встречается в словаре. Поскольку все ключи уникальные, там будет либо 0, либо 1. Соответственно, если ключ word пока в словаре counters не встречается, то есть он входит туда 0 раз, то, наверное, мы должны добавить его в словарь counters со значением 1. А иначе, иначе у нас уже есть такой ключ в словаре, и мы можем сделать ++ к этому значению — counters[word]. Так вот, оказывается, что этот код избыточен, потому что можно оставить просто вот эту строчку: ++counters[word]. И вот почему. Дело в том, что как только вы обратились к конкретному элементу словаря, конкретному ключу с помощью квадратных скобок, компилятору нужно уже создать эту самую пару ключа и значения, с этим ключом и с каким-то значением по умолчанию. В данном случае как только вы обращаетесь к какому-то ключу, если этот ключ был, то компилятор, по сути, возвращает отсюда ссылку на него и вы делаете успешно ++ — увеличиваете на 1 значение. А если такого ключа еще не было, компилятор его добавляет со значением 0. Потому что целое число по умолчанию — это 0. Поэтому этот код будет работать ровно так, как надо. Давайте это проверим, вызвав функцию PrintMap от словаря counters. Компилируем код, запускаем и видим, что строчка one, слово one встречается два раза, а строчка two встречается один раз. Итак, можно писать очень простой код. Давайте все-таки еще раз покажем, что от одного лишь простого обращения к несуществующему ключу размер словаря может измениться. Для этого давайте будем после каждой операции, давайте перед каждой операцией будем выводить этот словарь, и в самом конце тоже выведем. И при этом выведем еще сразу размер словаря, вызвав метод size. Size: m.size(). Компилируем код, запускаем и что же видим? В самом начале перед первым словом размер словаря был нулевым, в нем не было ничего. Затем мы добавили в него первое слово, по сути, добавили, просто вызвав оператор «квадратные скобки». Размер словаря теперь 1, и там просто одна строчка one. Затем у нас добавилось слово two, и размер словаря стал 2, и затем мы увеличили значение для ключа one. Итак, всего лишь обращение к несуществующему ключу может увеличить размер словаря. Это можно продемонстрировать еще одним примером. Давайте сделаем буквально вот так: мы создали словарь, еще ничего с ним не сделали, просто обратились к несуществующему ключу, даже просто ключу "a". Посмотрим, каким будет словарь после этого. Скомпилируем код, запустим и увидим, что от одного лишь простого обращения к ключу "a", которого в словаре до этого не было, он добавился в словарь со значением 0. Как мы еще можем использовать это удобное свойство словаря? Например, давайте сгруппируем все слова в каком-то наборе по первой букве. Для этого, наверное, я заменю единицу на тройку здесь, и теперь у меня двойка и тройка начинаются с одной и той же буквы t. И я могу сгруппировать эти слова по первой букве. Какой мне словарь теперь нужен? Теперь мне нужен словарь из символов, потому что ключом будет первая буква, в набор слов, вектор этих самых слов. Назовем grouped_words словарь. Как нам его заполнить? Нам нужно опять же проитерироваться по всем словам с помощью константной ссылки. И для каждого слова взять, собственно, его первую букву, по которой мы будем группировать, обратиться к соответствующему ключу словаря. И, поскольку вот от одного такого обращения этот ключ добавится в словарь, если его там не было, с пустым вектором, потому что вектор по умолчанию — это пустой вектор, я могу сразу сделать push_back, push_back от слова. Кажется, все готово, осталось только вывести этот словарь, поскольку у него специфический формат, я заново напишу цикл for. Соответственно, я перебираю все пары ключ-значение в этом словаре. [ШУМ] Соответственно, ключ — это символ, давайте я его выведу на отдельной строке. Ключ лежит в поле first. И затем я выведу все слова, которые соответствуют этому ключу. Соответственно, я должен проитерироваться константной ссылкой по всем словам из значения большого словаря, а значение — это item.second. И каждое слово вывести — соответственно, выводим слово, потом — давайте они все будут на одной строчке, поэтому выведу пробел. И в конце строки выведу «конец строки». Итак, я могу скомпилировать код, запустить, и, наконец, посмотреть на свой словарь. Итак, в словаре есть ключ 'o' со значением one, с вектором длины 1 — one, и ключ 't', которому соответствует вектор из двух строчек — two и three. Итак, что можно делать со словарями? Можно обращаться к конкретному элементу с помощью квадратных скобок, как к вектору, при этом если ключа не было, то он добавится. Можно удалять элементы с помощью метода erase, можно проверять наличие конкретного ключа в словаре с помощью метода count. Ну и, конечно, можно выводить словари с помощью обычного цикла for.