Как узнать, существует ли данный ключ в C ++ std :: map

354

Я пытаюсь проверить, находится ли данный ключ на карте, и несколько не может этого сделать:

typedef map<string,string>::iterator mi;
map<string, string> m;
m.insert(make_pair("f","++--"));
pair<mi,mi> p = m.equal_range("f");//I'm not sure if equal_range does what I want
cout << p.first;//I'm getting error here

так как я могу напечатать то, что находится в p?

  • 0
    std::pair<iterator,bool> insert( const value_type& value ); Что за бул возвращается? это говорит, если ключ уже присутствует или нет?
Теги:
dictionary
stl

12 ответов

532
Лучший ответ

Используйте map::find

if ( m.find("f") == m.end() ) {
  // not found
} else {
  // found
}
  • 86
    Если вы просто хотите проверить, существует ли определенный ключ, вам, вероятно, лучше использовать map::count
  • 7
    @tomsmeding В std :: map есть только один ключ. Таким образом, число будет либо 0, либо 1. Является ли один более эффективным, чем другой?
Показать ещё 5 комментариев
264

Чтобы проверить, существует ли конкретный ключ на карте, используйте функцию-член count одним из следующих способов:

m.count(key) > 0
m.count(key) == 1
m.count(key) != 0

документация для map::find говорит: "Другая функция-член, map::count, может использоваться, чтобы просто проверить, существует ли конкретный ключ."

documentation для map::count говорит:" Поскольку все элементы в контейнере карты уникальны, функция может возвращать только 1 (если элемент) или ноль (в противном случае).

Чтобы получить значение с карты с помощью ключа, который, как вы знаете, существует, используйте map:: at:

value = m.at(key)

В отличие от map:: operator [], map::at не создаст новый ключ на карте, если указанный ключ не существует.

  • 28
    Если вы собираетесь выполнить обе операции, проверьте, существует ли она, а затем что-то с этим сделать. Вместо этого используйте find . second атрибут итератора, возвращаемый функцией find может использоваться для получения значения ключа. Если вы используете count то at или operator[] вы выполняете две операции, когда вы могли бы использовать только одну.
  • 4
    Это должен быть выбранный ответ.
Показать ещё 5 комментариев
30

Вы можете использовать .find():

map<string,string>::iterator i = m.find("f");

if (i == m.end()) { /* Not found */ }
else { /* Found, i->first is f, i->second is ++-- */ }
12
m.find == m.end() // not found 

Если вы хотите использовать другой API, то найдите m.count(c)>0

 if (m.count("f")>0)
      cout << " is an element of m.\n";
    else 
      cout << " is not an element of m.\n";
12

Я думаю, вы хотите map::find. Если m.find("f") равно m.end(), ключ не был найден. В противном случае find возвращает итератор, указывающий на найденный элемент.

Ошибка связана с тем, что p.first является итератором, который не работает для вставки потока. Измените свою последнюю строку на cout << (p.first)->first;. p - пара итераторов, p.first - итератор, p.first->first - ключевая строка.

В карте может быть только один элемент для заданного ключа, поэтому equal_range не очень полезен. Он определен для карты, потому что он определен для всех ассоциативных контейнеров, но это намного интереснее для мультимапа.

  • 0
    На самом деле, поскольку это пара итераторов для карты, она должна быть "cout << p.first-> first;"
  • 0
    Я исправил свой ответ, спасибо. Вот что я получаю за то, что не скомпилировал мой код. И вы правы (в удаленном комментарии) в отношении проверки на достоверность, но я просто пытался объяснить, почему он не смог напечатать p.first, а не потому, что он недействителен - мы знаем, что «f» будет найдено. Поскольку я вообще не рекомендую использовать equal_range, я не собираюсь показывать код проверки ошибок для этого.
Показать ещё 2 комментария
4
template <typename T, typename Key>
bool key_exists(const T& container, const Key& key)
{
    return (container.find(key) != std::end(container));
}

Конечно, если бы вы хотели получить fancier, вы всегда могли бы отформатировать функцию, которая также приняла найденную функцию и не найденную функцию, что-то вроде этого:

template <typename T, typename Key, typename FoundFunction, typename NotFoundFunction>
void find_and_execute(const T& container, const Key& key, FoundFunction found_function, NotFoundFunction not_found_function)
{
    auto& it = container.find(key);
    if (it != std::end(container))
    {
        found_function(key, it->second);
    }
    else
    {
        not_found_function(key);
    }
}

И используйте его следующим образом:

    std::map<int, int> some_map;
    find_and_execute(some_map, 1,
        [](int key, int value){ std::cout << "key " << key << " found, value: " << value << std::endl; },
        [](int key){ std::cout << "key " << key << " not found" << std::endl; });

Недостатком этого является хорошее имя, "find_and_execute" неудобно, и я не могу придумать ничего лучше с моей головы...

2
map<string, string> m;

существует ключ проверки или нет, и возвращается число событий (0/1 в карте):

int num = m.count("f");  
if (num>0) {    
    //found   
} else {  
    // not found  
}

существует ключ проверки или нет, и возвращает итератор:

map<string,string>::iterator mi = m.find("f");  
if(mi != m.end()) {  
    //found  
    //do something to mi.  
} else {  
    // not found  
}  

в вашем вопросе ошибка, вызванная плохой перегрузкой operator<<, потому что p.first - map<string, string>, вы не можете ее распечатать. попробуй это:

if(p.first != p.second) {
    cout << p.first->first << " " << p.first->second << endl;
}
  • 1
    У вас есть опечатка. Измените «cout» на «count»
  • 1
    И эта опечатка действительно может кого-то сбить с толку, так как cout может означать нечто совсем иное, чем count
2

Будьте внимательны при сравнении результата поиска с концом, как и для map 'm', поскольку все ответы имеют сделано выше    map:: iterator я = m.find( "f" );

 if (i == m.end())
 {
 }
 else
 {
 }  

вам не следует пытаться выполнять какую-либо операцию, такую ​​как печать ключа или значения с помощью итератора i, если его значение равно m.end(), иначе это приведет к ошибке сегментации.

  • 0
    Хорошее упоминание, действительно.
0

С++ 20 дает нам std::map::contains для этого.

#include <iostream>
#include <string>
#include <map>

int main()
{
    std::map<int, std::string> example = {{1, "One"}, {2, "Two"}, 
                                     {3, "Three"}, {42, "Don\'t Panic!!!"}};

    if(example.contains(42)) {
        std::cout << "Found\n";
    } else {
        std::cout << "Not found\n";
    }
}
  • 3
    Я думаю, я скажу это: наконец.
  • 0
    Это потрясающе!
0

Сравнивая код std:: map:: find и std:: map:: count, я бы сказал, что первое может принести некоторое преимущество в производительности:

const_iterator find(const key_type& _Keyval) const
    {   // find an element in nonmutable sequence that matches _Keyval
    const_iterator _Where = lower_bound(_Keyval); // Here one looks only for lower bound
    return (_Where == end()
        || _DEBUG_LT_PRED(this->_Getcomp(),
            _Keyval, this->_Key(_Where._Mynode()))
                ? end() : _Where);
    }

size_type count(const key_type& _Keyval) const
    {   // count all elements that match _Keyval
    _Paircc _Ans = equal_range(_Keyval); // Here both lower and upper bounds are to be found, which is presumably slower.
    size_type _Num = 0;
    _Distance(_Ans.first, _Ans.second, _Num);
    return (_Num);
    }
-2

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

typedef map<double, double> TestMap;
TestMap testMap;
pair<map<double,double>::iterator,bool> controlMapValues;

controlMapValues= testMap.insert(std::pair<double,double>(x,y));
if (controlMapValues.second == false )
{
    TestMap::iterator it;
    it = testMap.find(x);

    if (it->second == y)
    {
        cout<<"Given value is already exist in Map"<<endl;
    }
}

Это полезный метод.

  • 0
    Как новичок в программировании на C ++, мне действительно любопытно, почему этот ответ опущен. Почему этот ответ непопулярен?
  • 1
    @ gromit190, потому что он использует целую другую структуру данных, чтобы увидеть, существует ли ключ, когда std :: map уже имеет эту возможность. Это также потребовало бы синхронизации между двумя структурами данных, которая является зависимостью, с которой никто не хочет иметь дело.
-4
map <int , char>::iterator itr;
    for(itr = MyMap.begin() ; itr!= MyMap.end() ; itr++)
    {
        if (itr->second == 'c')
        {
            cout<<itr->first<<endl;
        }
    }
  • 2
    Пожалуйста, уточните ваш код. Фрагмент без каких-либо объяснений, как правило, не помогает в долгосрочной перспективе.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню