621

I'm trying to check if a given key is in a map and somewhat can't do it:

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

so how can I print what is in p?

Antonio
  • 19,451
  • 13
  • 99
  • 197
There is nothing we can do
  • 23,727
  • 30
  • 106
  • 194

15 Answers15

951

Use map::find and map::end:

if (m.find("f") == m.end()) {
  // not found
} else {
  // found
}
Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
  • 145
    If you just want to check whether a certain key exists, you'd probably rather use [`map::count`](http://www.cplusplus.com/reference/map/map/count/) – tomsmeding Aug 28 '13 at 16:17
  • 12
    @tomsmeding There is only a single key in a std::map. So count will either be 0 or 1. Is one more efficient than the other? – goelakash Jul 17 '15 at 07:38
  • 45
    @goelakash hardly; it's just that `count` returns an `int` while `find` returns a whole iterator. You save the construction of the iterator :) Obviously, if you afterwards are going to *use* the value if it exists, use find and store its result. – tomsmeding Jul 17 '15 at 08:04
  • 12
    @tomsmeding If you're using a multimap, you'd have to look through the entire container. In which case, find() may be quicker. – Trevor Hickey Sep 21 '16 at 18:03
  • 1
    what is its time compelxity. Will it be linear as the method will iterate through the whole map – Nikhil Rathore Dec 13 '18 at 14:56
  • 1
    @NikhilRathore The time complexity of std::map::find and ::count are both logarithmic because it is an [ordered map](https://en.cppreference.com/w/cpp/container/map), which does not have to test every item in the map. The time complexity of std::unordered_map::find and ::count are ['kind of' constant](https://en.cppreference.com/w/cpp/container/unordered_map) (See [here](https://stackoverflow.com/questions/2771368/can-hash-tables-really-be-o1) to understand why I say 'kind of'). This is because it uses a hash table which allows it to often jump straight to the correct memory location. – cdgraham Mar 19 '19 at 17:39
  • 40
    **To those who are looking for speed:** `count` and `find` are nearly identical in speed when using maps that require unique keys. (1) If you don't need the elements to maintain a specific order, use [std::unordered_map](https://en.cppreference.com/w/cpp/container/unordered_map), which has [near-constant](https://stackoverflow.com/q/2771368/) look-ups and can be very beneficial when storing more than a few pairs. (2) If you want to use the value if it exists, store the result of ::find and use the iterator to prevent 2 look-ups: `auto it = m.find("f"); if (it != m.end()) {/*Use it->second*/}` – cdgraham Mar 19 '19 at 17:55
387

To check if a particular key in the map exists, use the count member function in one of the following ways:

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

The documentation for map::find says: "Another member function, map::count, can be used to just check whether a particular key exists."

The documentation for map::count says: "Because all elements in a map container are unique, the function can only return 1 (if the element is found) or zero (otherwise)."

To retrieve a value from the map via a key that you know to exist, use map::at:

value = m.at(key)

Unlike map::operator[], map::at will not create a new key in the map if the specified key does not exist.

DavidRR
  • 18,291
  • 25
  • 109
  • 191
  • 37
    If you are going to do both operations, check if it exists and then do something about it. Use `find` instead. The `second` attribute of the iterator returned by `find` can be used retrieve the value of the key. If you use `count` then `at` or `operator[]` you are performing two operations when you could have used only one. – OdraEncoded Jun 13 '14 at 21:24
  • 1
    You don't need to do > 0, == 1 or != 0; that's the exact check C++ does in an if statement (condition != 0), so you can just use `if(m.count(key))` – jv110 Dec 16 '16 at 20:50
  • 12
    @jv110 The Microsoft C++ compiler [issues a warning](http://stackoverflow.com/q/4968033/1497596) when it encounters a cast from `int` to `bool`. Though there are other C++ compilers that do not issue a similar warning, I prefer using an [explicit comparison](http://stackoverflow.com/a/4968060/1497596) to make the intent clear and enhance readability. Note that other languages such as C# [forbid such an implicit conversion](http://stackoverflow.com/a/6571505/1497596) to prevent the possibility of introducing subtle programming errors. – DavidRR Dec 17 '16 at 15:38
  • what is time complexity of count? Is it just O(1) operation? – Mazeryt May 14 '17 at 12:18
  • 1
    @Mazeryt Given that we are talking about a class in the C++ standard library, I would certainly assume so. For a language-agnostic discussion of your question, see [Can hash tables really be O(1)?](http://stackoverflow.com/questions/2771368). – DavidRR May 14 '17 at 15:10
  • 1
    @Mazeryt No, `std::map::count` is actually [logarithmic](https://en.cppreference.com/w/cpp/container/map/count). This is because [C++ std::map](https://en.cppreference.com/w/cpp/container/map) is an ordered map, so it does not use a hash table. However, the C++ standard library also has `std::unordered_map`, where `std::unordered_map::count` is [O(1) often](https://en.cppreference.com/w/cpp/container/unordered_map/count). See [DavidRR's link](https://stackoverflow.com/questions/2771368/can-hash-tables-really-be-o1) to know why even std::unordered_map::count is not always O(1). – cdgraham Mar 19 '19 at 17:32
  • I like this one more than the find() thingy - it's way more expressive – ataraxis Feb 03 '21 at 22:08
  • I don't get the `m.count(key) > 0` case. A map is an associative array that is a dictionary. Keys are unique hence you cannot have multiple equivalent keys (obviously does not apply to the values associated with those). – rbaleksandar Aug 15 '22 at 08:01
166

C++20 gives us std::map::contains to do that.

#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";
    }
}
Denis Sablukov
  • 3,360
  • 2
  • 26
  • 31
55

You can use .find():

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

if (i == m.end()) { /* Not found */ }
else { /* Found, i->first is f, i->second is ++-- */ }
Andreas Bonini
  • 44,018
  • 30
  • 122
  • 156
45

C++17 simplified this a bit more with an If statement with initializer. This way you can have your cake and eat it too.

if ( auto it{ m.find( "key" ) }; it != std::end( m ) ) 
{
    // Use `structured binding` to get the key
    // and value.
    const auto&[ key, value ] { *it };

    // Grab either the key or value stored in the pair.
    // The key is stored in the 'first' variable and
    // the 'value' is stored in the second.
    const auto& mkey{ it->first };
    const auto& mvalue{ it->second };

    // That or just grab the entire pair pointed
    // to by the iterator.
    const auto& pair{ *it };
} 
else 
{
   // Key was not found..
}
WBuck
  • 5,162
  • 2
  • 25
  • 36
20
m.find == m.end() // not found 

If you want to use other API, then find go for 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";
aJ.
  • 34,624
  • 22
  • 86
  • 128
13

I think you want map::find. If m.find("f") is equal to m.end(), then the key was not found. Otherwise, find returns an iterator pointing at the element found.

The error is because p.first is an iterator, which doesn't work for stream insertion. Change your last line to cout << (p.first)->first;. p is a pair of iterators, p.first is an iterator, p.first->first is the key string.

A map can only ever have one element for a given key, so equal_range isn't very useful. It's defined for map, because it's defined for all associative containers, but it's a lot more interesting for multimap.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • Actually, because it is a pair of iterators to a map, it should be "cout << p.first->first;" – stefaanv Dec 21 '09 at 13:06
  • I've fixed my answer, thanks. That's what I get for not compiling my code. And you're right (in a deleted comment) about checking for validity, but I was just trying to explain why he couldn't print p.first, and it's not because it's invalid - we know "f" will be found. Since I don't recommend using equal_range at all, I'm not about to show error-checking code for that. – Steve Jessop Dec 21 '09 at 13:12
  • Wow, you're really scanning SO. I was just adding it for completeness, because your point was clear. I added the validity check to my previous answer, but your response beated me, so I deleted it, because it didn't add that much anyway, as you mentioned. – stefaanv Dec 21 '09 at 16:10
9
template <typename T, typename Key>
bool key_exists(const T& container, const Key& key)
{
    return (container.find(key) != std::end(container));
}

Of course if you wanted to get fancier you could always template out a function that also took a found function and a not found function, something like this:

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);
    }
}

And use it like this:

    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; });

The downside to this is coming up with a good name, "find_and_execute" is awkward and I can't come up with anything better off the top of my head...

Lambage
  • 367
  • 3
  • 8
6
map<string, string> m;

check key exist or not, and return number of occurs(0/1 in map):

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

check key exist or not, and return iterator:

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

in your question, the error caused by bad operator<< overload, because p.first is map<string, string>, you can not print it out. try this:

if(p.first != p.second) {
    cout << p.first->first << " " << p.first->second << endl;
}
log0
  • 10,489
  • 4
  • 28
  • 62
hustljian
  • 965
  • 12
  • 9
3

Be careful in comparing the find result with the the end like for map 'm' as all answer have done above map::iterator i = m.find("f");

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

you should not try and perform any operation such as printing the key or value with iterator i if its equal to m.end() else it will lead to segmentation fault.

Invictus
  • 4,028
  • 10
  • 50
  • 80
0

Comparing the code of std::map::find and std::map::count, I'd say the first may yield some performance advantage:

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);
    }
Hope
  • 1,051
  • 13
  • 17
0

Both find() and contains() can be used. According to the documentation. Both methods take constant time on average and linear time in the worst case.

-1

I know this question already has some good answers but I think my solution is worth of sharing.

It works for both std::map and std::vector<std::pair<T, U>> and is available from C++11.

template <typename ForwardIterator, typename Key>
bool contains_key(ForwardIterator first, ForwardIterator last, Key const key) {
    using ValueType = typename std::iterator_traits<ForwardIterator>::value_type;

    auto search_result = std::find_if(
        first, last,
        [&key](ValueType const& item) {
            return item.first == key;
        }
    );

    if (search_result == last) {
        return false;
    } else {
        return true;
    }
}
NutCracker
  • 11,485
  • 4
  • 44
  • 68
-6
map <int , char>::iterator itr;
    for(itr = MyMap.begin() ; itr!= MyMap.end() ; itr++)
    {
        if (itr->second == 'c')
        {
            cout<<itr->first<<endl;
        }
    }
  • 4
    Please elaborate on your code. A snippet without any explanation doesn't tend to be helpful in a long run. – iBug Dec 15 '17 at 02:11
-7

If you want to compare pair of map you can use this method:

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;
    }
}

This is a useful technique.

Trevor Hickey
  • 36,288
  • 32
  • 162
  • 271
EmreS
  • 159
  • 1
  • 3
  • 15
  • As beginner with C++ programming, I'm really curious why this answer is downvoted. Why is this answer unpopular? – birgersp Oct 11 '17 at 07:40
  • 4
    @gromit190 because it's using a whole other data structure to see if the key exists when std::map has this capability already. This would also require synchronisation between the two data structures which is a dependency no one wants to deal with. – Lambage Jul 12 '18 at 13:01