Определить, содержит ли карта значение для ключа?

Каков наилучший способ определить, содержит ли карта STL значение для заданного ключа?

#include <map>

using namespace std;

struct Bar
{
    int i;
};

int main()
{
    map<int, Bar> m;
    Bar b = {0};
    Bar b1 = {1};

    m[0] = b;
    m[1] = b1;

    //Bar b2 = m[2];
    map<int, Bar>::iterator iter = m.find(2);
    Bar b3 = iter->second;

}

Рассматривая это в отладчике, похоже, что iter - это всего лишь данные мусора.

Если я раскомментирую эту строку:

Bar b2 = m[2]

Отладчик показывает, что b2 - {i = 0}. (Я предполагаю, что это означает, что использование индекса undefined возвращает структуру со всеми пустыми/неинициализированными значениями?)

Ни один из этих методов не настолько велик. Мне бы очень понравился такой интерфейс:

bool getValue(int key, Bar& out)
{
    if (map contains value for key)
    {
        out = map[key];
        return true;
    }
    return false;
}

Есть ли что-то в этих строках?

Ответ 1

Есть ли что-то в этих строках?

Нет. С классом stl map вы используете ::find() для поиска карты и сравниваете возвращаемый итератор с std::map::end()

так

map<int,Bar>::iterator it = m.find('2');
Bar b3;
if(it != m.end())
{
   //element found;
   b3 = it->second;
}

Очевидно, вы можете написать свою собственную процедуру getValue(), если хотите (также на С++, нет оснований использовать out), но я бы заподозрил, что как только вы получите возможность использовать std::map::find(), вы выиграли ' я хочу тратить ваше время.

Также ваш код немного ошибочен:

m.find('2'); будет искать карту для ключевого значения '2'. IIRC компилятор С++ будет неявно преобразовывать '2' в int, что приводит к числовому значению для кода ASCII для '2', который не является тем, что вы хотите.

Так как ваш ключевой тип в этом примере int, вы хотите выполнить поиск следующим образом: m.find(2);

Ответ 2

Пока карта не является мультимапом, одним из самых элегантных способов было бы использовать метод count

if (m.count(key))
    // key exists

Счет будет равен 1, если элемент действительно присутствует на карте.

Ответ 3

Он уже существует с поиском только не в этом точном синтаксисе.

if (m.find(2) == m.end() )
{
    // key 2 doesn't exist
}

Если вы хотите получить доступ к значению, если оно существует, вы можете сделать:

map<int, Bar>::iterator iter = m.find(2);
if (iter != m.end() )
{
    // key 2 exists, do something with iter->second (the value)
}

С С++ 0x и auto синтаксис проще:

auto iter = m.find(2);
if (iter != m.end() )
{
    // key 2 exists, do something with iter->second (the value)
}

Я рекомендую вам привыкнуть к нему, а не пытаться создать новый механизм для его упрощения. Возможно, вы сможете сократить немного кода, но подумайте о стоимости этого. Теперь вы ввели новую функцию, которую люди, знакомые с С++, не смогут распознать.

Если вы хотите реализовать это, несмотря на эти предупреждения, то:

template <class Key, class Value, class Comparator, class Alloc>
bool getValue(const std::map<Key, Value, Comparator, Alloc>& my_map, int key, Value& out)
{
    typename std::map<Key, Value, Comparator, Alloc>::const_iterator it = my_map.find(key);
    if (it != my_map.end() )
    {
        out = it->second;
        return true;
    }
    return false;
}

Ответ 4

Я только что заметил, что с С++ 20 у нас будет

bool std::map::contains( const Key& key ) const;

Это вернет true, если map содержит элемент с ключом key.

Ответ 5

amap.find возвращает amap::end, когда он не находит то, что вы ищете - вы должны проверить это.

Ответ 6

Проверьте возвращаемое значение find по сравнению с end.

map<int, Bar>::iterator it = m.find('2');
if ( m.end() != it ) { 
  // contains
  ...
}

Ответ 7

Вы можете создать свою функцию getValue со следующим кодом:

bool getValue(const std::map<int, Bar>& input, int key, Bar& out)
{
   std::map<int, Bar>::iterator foundIter = input.find(key);
   if (foundIter != input.end())
   {
      out = foundIter->second;
      return true;
   }
   return false;
}

Ответ 8

Чтобы кратко суммировать некоторые другие ответы:

Если вы еще не используете C++ 20, вы можете написать свою собственную функцию mapContainsKey:

bool mapContainsKey(std::map<int, int>& map, int key)
{
  if (map.find(key) == map.end()) return false;
  return true;
}

Если вы хотите избежать многих перегрузок для map против unordered_map и различных типов ключей и значений, вы можете сделать это функцией template.

Если вы используете C++ 20 или более позднюю версию, будет встроенная функция contains:

std::map<int, int> myMap;

// do stuff with myMap here

int key = 123;

if (myMap.contains(key))
{
  // stuff here
}

Ответ 9

Если вы хотите определить, есть ли ключ на карте или нет, вы можете использовать функцию-функцию find() или count() для карты. Функция find, которая используется здесь в примере, возвращает итератор в элемент или карту:: end в противном случае. В случае подсчета счетчик возвращает 1, если найден, иначе он возвращает ноль (или иначе).

if(phone.count(key))
{ //key found
}
else
{//key not found
}

for(int i=0;i<v.size();i++){
    phoneMap::iterator itr=phone.find(v[i]);//I have used a vector in this example to check through map you cal receive a value using at() e.g: map.at(key);
    if(itr!=phone.end())
        cout<<v[i]<<"="<<itr->second<<endl;
    else
        cout<<"Not found"<<endl;
}

Ответ 10

Boost multindex может использоваться для правильного решения. Следующее решение не является лучшим вариантом, но может оказаться полезным в немногих случаях, когда пользователь присваивает значение по умолчанию, например 0 или NULL, при инициализации и хочет проверить, было ли изменено значение.

Ex.
< int , string >
< string , int > 
< string , string > 

consider < string , string >
mymap["1st"]="first";
mymap["second"]="";
for (std::map<string,string>::iterator it=mymap.begin(); it!=mymap.end(); ++it)
{
       if ( it->second =="" ) 
            continue;
}