Как избежать дублирования пар / найти пару в multimap?
У меня есть (рабочий) код, который использует multimap<string,string>
. Я хотел бы изменить его, чтобы запретить дубликаты значений на одном ключе (очевидно, разные значения на одном ключе в порядке, иначе я бы не использовал multimap).
удивительно, что тип не кажется иметь встроенный способ избежать дубликатов или найти пару ключ-значение (только чтобы найти ключ). Но я полагаю, что у кого-то на SO должен быть готовый обходной путь. Кто?
4 ответов
std::map<std::string, std::set<std::string>>
казалось бы, именно те свойства, которые вы ищете (хотя и уступает сложности unordered_map
и unordered_set
).
вот что я придумал:
template<class K, class V>
typename multimap<K, V>::const_iterator find_pair(const multimap<K, V>& map, const pair<K, V>& pair)
{
typedef multimap<K, V>::const_iterator it;
std::pair<it,it> range = map.equal_range(pair.first);
for (it p = range.first; p != range.second; ++p)
if (p->second == pair.second)
return p;
return map.end();
}
template<class K, class V>
bool insert_if_not_present(multimap<K, V>& map, const pair<K, V>& pair)
{
if (find_pair(map, pair) == map.end()) {
map.insert(pair);
return true;
}
return false;
}
(Это не эффективно, когда есть большое количество значений, подключенных к одному ключу, но в моем случае есть несколько значений для каждого ключа.)
мое предложение вам было бы обернуть multimap в класс и просто выполнить проверку в методе, где вы добавляете что-то в карту. Остальные функции просто перейдут к методам multimap. Это делает много кода котельной плиты, но если вам когда-либо понадобится сделать другие типы проверок, это будет проще.
Кажется,
std::set<std::pair<std::string,std::string>>>
будет иметь именно те свойства, которые вы ищете.
однако это не карта и не multimap. Вы можете сохранить как multimap, так и набор пар ключей, значений или создать этот набор только для проверки согласованности.
Я бы использовал этот набор и создал адаптер над ним для интерфейса multimap. Возможно, это не самое простое решение для реализации, но с лучшей эффективностью работы.
см. " шаблон дизайна адаптера" вопросы для справок.
[обновление]
посмотреть мои пример работающего в качестве отправной точки.
Е. Г. как перебрать все значения ключа - см.:
typedef std::set<std::pair<std::string, std::string> > ssset;
ssset::iterator get_key(ssset& s, std::string key)
{
ssset::iterator it = s.lower_bound(std::make_pair(key, ""));
if (it != s.end() && it->first == key) return it;
return s.end();
}
for (ssset::iterator it = get_key(s, "abc"); it != s.end() && it->first == "abc"; ++it)
std::cout << it->first << "->" << it->second << std::endl;