[БЕЗ_ЗВУКА] Итак, в прошлом видео мы увидели в действии итераторы и проверили их на примере вектора из строк. Но все-таки у нас есть и другие контейнеры. Давайте посмотрим, как работает итератор от этих контейнеров. Увидим, что, по сути, они работают точно так же. Какие контейнеры мы помним? Например, множество. Давайте возьмем наш вектор языков и заменим его на множество языков. Казалось бы, почему нет? Соответственно, я теперь импортирую set. И здесь у меня будет множество строк. Я могу сразу вызвать от него свою шаблонную функцию PrintRange, увидеть, что она для него работает. Точно так же PrintRange (begin(langs), end(langs). Компилирую, запускаю и вижу, что у меня также выявились на языке программирования, только теперь в отсортированном порядке, потому что у меня все-таки множество. Хорошо. Во множестве у нас были методы для поиска элементов. Мы использовали метод count. Есть также метод, который возвращает итератор на конкретный элемент, который он нашел. Метод ожидаемый называется find. Я могу, скажем, найти в этом множестве C++, сохранить результат в какой-то итератор. Что можно сделать с этим итератором? Например, я могу вызвать PrintRange от начала моего множества до этого итератора. Какой у этого смысл? Когда я показывал это на векторе, в этом, казалось бы, не было никакого смысла, а теперь у меня получатся все названия языков, которые стоят перед C++ в отсортированном порядке, в том порядке, в котором элементы хранятся во множестве. То есть я получу все строчки, которые меньше, чем в C++. Давайте я скомпилирую, запущу и это увижу. Итак, у меня C и C# ровно. Они не меньше C++. А если я теперь выведу диапазон от этого итератора до end(langs), у меня получатся все языки, которые больше либо равны лексикографически как строки, чем в C++. Компилирую, запускаю, и у меня, по сути, в итоге вывелся весь диапазон, как мы и показывали в прошлом видео. Хорошо. Какие еще есть контейнеры? Например, словарь. Давайте сделаем словарь, в котором снова будут возрасты языков. Подключу библиотеку map. [БЕЗ_ЗВУКА] Заодно увидим, как нам итерироваться по словарю с помощью итераторов. Итак, снова Python, которому 26 лет, C++ возрастом 34 года, C возрастом 45 лет, Java возрастом 22 года и C# возрастом 17 лет. Вот у меня словарь, ключ, значение. Ключи — это строки, значение — это целые числа. map<string, int>. Как мне вывести этот словарь? Если я захочу вызвать функцию PrintRange для этого словаря, то у меня должен быть оператор вывода в поток для *it. Какой тип у элементов словаря? Когда вы итерировались по нему range based for loop, у вас этот тип был парой. Соответственно, и здесь *it — это пара. Если вы не переопределите оператор вывода для пары, как вы это уже умеете, то у вас эта функция не скомпилируется. Можем, в принципе, попробовать. Вот мы нашли C++ все так же и попробуем вызвать PrintRange. Я пробую скомпилировать. И у меня очень много ошибок, ничего не скомпилировалось. В частности, можно увидеть, что, давайте посмотрим поближе, что у меня нет оператора вывода в поток для того, для чего он должен был бы быть. Итак, мы увидели, что у меня не компилируется вызов функции PrintRange для словаря. Тогда давайте я для словаря напишу отдельную функцию, которая будет выводить отдельно ключи, отдельно значения. Как я это сделаю? Я возьму нашу функцию PrintRange, назову ее PrintMapRange. И чем она будет отличаться от функции PrintRange? Я буду вызывать не *it, чтобы не пытаться вывести пару в поток, а выведу сначала поле first, а затем через разделитель — поле second. it->second. Давайте я попробую теперь вызвать функцию PrintMapRange от первого диапазона и от второго диапазона, разобью их переводом строки, скомпилирую, запущу и вижу, что у меня вывелась сначала часть словаря с ключами меньшими, чем в C++. C со значением 45, C# со значением 17 и так далее. И затем вывелась остальная часть словаря, у которой ключи больше либо равны, чем в C++. Итак, я могу спокойно итерироваться по словарю и с помощью удобного оператора «стрелочка» обращаться к ключам ->first и к значениям ->second.