11.2.1. Определение ассоциативного контейнера
map<string, size_t> word_count; // пустая карта
// списочная инициализация
set<string> exclude = {"the", "but", "and", "or", "an", "a",
"The", "But", "And", "Or", "An", "A"};
// три элемента; authors сопоставляет фамилию с именем
map<string, string> authors = { {"Joyce", "James"},
{"Austen", "Jane"},
{"Dickens", "Charles"} };
Как обычно, тип инициализаторов должен быть преобразуемым в тип контейнера. Типом элемента набора является тип ключа.
При инициализации карты следует предоставить и ключ, и значение. Каждая пара ключ-значение заключается в фигурные скобки, {ключ, значение}, означая, что вместе элементы формируют единый элемент карты. Первый элемент каждой пары — это ключ, второй — значение. Таким образом, карта authors сопоставляет фамилии с именами и инициализируется тремя элементами.
Инициализация контейнеров multimap и multiset
Ключи в контейнерах map и set должны быть уникальными; с каждым ключом может быть сопоставлен только один элемент. У контейнеров multimap и multiset такого ограничения нет; вполне допустимо несколько элементов с тем же ключом. Например, у использованной для подсчета слов карты должен быть только один элемент, содержащий некое слово. С другой стороны, у словаря может быть несколько определений того же слова.
Следующий пример иллюстрирует различия между контейнерами с уникальными ключами и таковыми с не уникальными ключами. Сначала необходимо создать вектор целых чисел ivec на 20 элементов: две копии каждого из целых чисел от 0 до 9 включительно. Этот вектор будет использован для инициализации контейнеров set и multiset:
// определить вектор из 20 элементов, содержащий две копии каждого
// числа от 0 до 9
vector<int> ivec;
for (vector<int>::size_type i = 0; i != 10; ++i) {
ivec.push_back(i);
ivec.push_back(i); // сдублировать каждое число
}
// iset содержит уникальные элементы ivec;
// miset содержит все 20 элементов
set<int> iset(ivec.cbegin(), ivec.cend());
multiset<int> miset(ivec.cbegin(), ivec.cend());
cout << ivec.size() << endl; // выводит 20
cout << iset.size() << endl; // выводит 10
cout << miset.size() << endl; // выводит 20
Хотя набор iset был инициализирован значениями всего контейнера ivec, он содержит только десять элементов: по одному для каждого уникального элемента вектора ivec. С другой стороны, контейнер miset содержит 20 элементов, сколько и вектор ivec.
Упражнения раздела 11.2.1
Упражнение 11.5. Объясните различие между картой и набором. Когда имеет смысл использовать один, а когда другой?
Упражнение 11.6. Объясните различия между набором и списком. Когда имеет смысл использовать один, а когда другой?
Упражнение 11.7. Определите карту, ключ которой является фамилией семьи, а значение — вектором имен детей. Напишите код, способный добавлять новые семьи и новых детей в существующие семьи.
Упражнение 11.8. Напишите программу, которая хранит исключенные слова в векторе, а не в наборе. Каковы преимущества использования набора?