C++: поиск по карте без использования итератора
Считайте, у меня есть это:
std::map<int, int> intMap;
intMap[11] = 21;
intMap[12] = 22;
intMap[13] = 23;
intMap[14] = 24;
int val = 0;
Когда я хочу найти значение map[11], если оно существует, и поместить его в val
Я использую:
std::map<int, int>::iterator it = intMap.find(11);
if(it != intMap.end())
val = it->second;
Есть ли способ сделать это без использования итератора? Я имею в виду, более короткий путь.
int val = intMap[11]
для меня это не вариант, так как он добавляет 11 в качестве ключа для intMap, если его там еще не было, что меня не интересует. см. здесь.
4 ответа
В с ++11 map
имеет новый метод под названием at(Key)
который вернет ссылку на сопоставленное значение или выдаст исключение, если Key
нет на карте.
В C++ вам понадобится промежуточный итератор.
Андре уже упоминает новый at()
функция. В других обстоятельствах может быть полезно следующее:
template <typename Map, typename K, typename T>
T get(Map &map, const K &key, T def) {
typename Map::const_iterator it = map.find(key);
return (it == map.end() ? def : it->second);
}
Используйте это как:
int val = get(intMap, 11, 0);
Вы также можете иметь const
version с преимуществом возврата ссылки (неконстантная версия возвращает значение, потому что возврат ссылки по умолчанию довольно ограничивающий):
template <typename Map, typename K, typename T>
const T& get(const Map &map, const K &key, const T &def) {
typename Map::const_iterator it = map.find(key);
return (it == map.end() ? def : it->second);
}
Просто для забавы, этот код является кратким, но он может потерять для ясности. Он делает то, что вы говорите в комментарии ниже: ничего в том случае, когда 11
нет на карте:
BOOST_FOREACH(const std::pair<int,int> &newval, intMap.equal_range(11)) {
val = newval.second;
}
Я думаю, это тоже может сработать:
int val;
if (intMap.count(11)) val = intMap[11];
Простая проверка наличия ключа...
Итак, в единственной строке с default_value, как это было предложено Karadoc:
int val = (intMap.count(x) ? intMap[x] : default_value);
Как правило, вам нужно как-то проверить наличие ключа. Однако вы можете написать некоторую функцию, которая выполняет проверку и дает значение, поэтому при вызове вы получите однострочную строку. Вам понадобится некоторое значение по умолчанию для случая, когда ключ не существует на карте. Вот быстрый вывод для этого:
template <class Map, class U>
auto getOrDefault(Map const& m, typename Map::key_type const& key, U&& default_val)
-> typename Map::mapped_type
{
auto pos = m.find(key);
return pos != m.end() ? pos->second : std::forward<U>(default_val);
}
template <class Map>
auto getOrDefault(Map const& m, typename Map::key_type const& key)
-> typename Map::mapped_type
{
typedef typename Map::mapped_type Value;
return getOrDefault(m, key, Value{});
}
//call:
int val = getOrDefault(intMap, 11); // 0 if key 11 does not exist
int val2 = getOrDefault(intMap, 42, -1); //-1 if key 42 does not exist
Примечание: мне не удалось дать default_val
аргумент по умолчанию - может быть, кто-то может помочь мне с этим. gcc 4.7.2 не смог вывести U
когда я пытался с U&& default_val = typename Map::mapped_type{}