11.3. Словари (map).

Словари предназначены для хранения произвольного количества элементов, в виде пар "ключ-значение". Причем к "ключам" предъявляется требование уникальности. Словари обладают широкими возможностями доступа к произвольным элементам и незначительными накладными расходами на операцию добавления нового элемента. Если в словарь вставляется новое значение по существующему ключу, то оно затирает старое значение в паре "ключ-значение".

Рисунок 11.3. Словарь экземпляров класса Film.


Поскольку словари хранят элементы в виде "ключ-значение", то принципы работы со словарями несколько отличаются от тех, что используются при работе со списками и векторами. Ниже приводится версия класса Film, которая будет использоваться для иллюстрации работы со словарем: class Film { public: Film(const QString &title = "", int duration = 0); QString title() const { return myTitle; } void setTitle(const QString &title) { myTitle = title; } int duration() const { return myDuration; } void setDuration(int minutes) { myDuration = minutes; } private: QString myTitle; int myDuration; }; Film::Film(const QString &title, int duration) { myTitle = title; myDuration = duration; } В этой версии отсутствует числовой идентификатор фильма, поскольку теперь он будет использоваться в качестве "ключа" в словаре. Кроме того, здесь отсутствуют операторы сравнения -- словари изначально упорядочивают элементы по ключу, но не по значению.

Класс словаря в STL определен под именем std::map<K, T>, в файле заголовка <map>. Ниже приводится пример объявления словаря, с целыми значениями в качестве ключей и Film -- в качестве значения:

map<int, Film> films; Эквивалент в Qt -- QMap<K, T>: QMap<int, Film> films; Наиболее естесственный способ заполнения словарей -- присваивать значение по заданному ключу: films[4812] = Film("A Hard Day's Night", 85); films[5051] = Film("Seven Days to Noon", 94); films[1301] = Film("Day of Wrath", 105); films[9227] = Film("A Special Day", 110); films[1817] = Film("Day for Night", 116); Итератор словаря предоставляет возможность доступа к паре "ключ-значение". Ключ извлекается с помощью (*it).first, а значение -- (*it).second: map<int, Film>::const_iterator it = films.begin(); while (it != films.end()) { cerr << (*it).first << ": " << (*it).second.title().ascii() << endl; ++it; } Большинство компиляторов допускают запись в виде it->first и it->second, но более переносимый вариант, все таки: (*it).first и (*it).second.

Итераторы словарей в Qt несколько отличаются от итераторов словарей в STL. В Qt ключ можно получить с помощью it.key(), а значение -- it.data():

QMap<int, Film>::const_iterator it = films.begin(); while (it != films.end()) { cerr << it.key() << ": " << it.data().title().ascii() < endl; ++it; } При обходе словаря в цикле, элементы словаря всегда упорядочены по значению ключа.

Для доступа к значениям словаря и их изменения может использоваться оператор "[ ]", однако, при попытке получить значение по несуществующему в словаре ключу, будет создан новый элемент словаря с заданным ключом и пустым значением. Чтобы избежать случайного создания пустых элементов, используйте функцию find(), чтобы получить искомый элемент:

map<int, Film>::const_iterator it = films.find(1817); if (it != films.end()) cerr << "Found " << (*it).second.title().ascii() << endl; Эта функция вернет итератор end(), если ключ отсутствует в словаре.

В примере выше, в качестве ключа использовались целые числа, однако, для этих целей могут использоваться и другие типы. Наиболее популярный -- QString, например:

map<QString, QString> actorToNationality; actorToNationality["Doris Day"] = "American"; actorToNationality["Greta Garbo"] = "Swedish"; Если необходимо хранить несколько значений с одинаковыми ключами, используйте multimap<K, T>. Если необходимо хранить одни только ключи, используйте set<K> или multiset<K>. Qt не имеет классов, эквивалентных приведенным.

Класс QMap<K, T> имеет несколько дополнительных функций, особенно удобных при работе с небольшими наборами данных. Функции QMap<K, T>::keys() и QMap<K, T>::values() возвращают списки QValueList ключей и значений словаря.