670

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?

0

15 Answers 15

1009

Use map::find and map::end:

if (m.find("f") == m.end()) {
  // not found
} else {
  // found
}
Sign up to request clarification or add additional context in comments.

7 Comments

If you just want to check whether a certain key exists, you'd probably rather use map::count
@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 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 If you're using a multimap, you'd have to look through the entire container. In which case, find() may be quicker.
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, which has near-constant 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*/}
|
406

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.

8 Comments

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.
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 The Microsoft C++ compiler issues a warning 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 to make the intent clear and enhance readability. Note that other languages such as C# forbid such an implicit conversion to prevent the possibility of introducing subtle programming errors.
@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)?.
@Mazeryt No, std::map::count is actually logarithmic. This is because C++ std::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. See DavidRR's link to know why even std::unordered_map::count is not always O(1).
|
205

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

1 Comment

Great! Good thing I scrolled down here. Maybe edit the accepted answer and add it to it?
57

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 ++-- */ }

Comments

54

C++17 simplified this a bit more with an If statements 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..
}

Comments

21
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";

Comments

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.

3 Comments

Actually, because it is a pair of iterators to a map, it should be "cout << p.first->first;"
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.
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.
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...

Comments

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

2 Comments

You have a typo. Change "cout" to "count"
And that typo can really throw someone off, as the cout can mean something very different than count
2

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.

Comments

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

Comments

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

Comments

-1

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.

Comments

-7
map <int , char>::iterator itr;
    for(itr = MyMap.begin() ; itr!= MyMap.end() ; itr++)
    {
        if (itr->second == 'c')
        {
            cout<<itr->first<<endl;
        }
    }

1 Comment

Please elaborate on your code. A snippet without any explanation doesn't tend to be helpful in a long run.
-8

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.

2 Comments

As beginner with C++ programming, I'm really curious why this answer is downvoted. Why is this answer unpopular?
@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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.