69

So there seem to be two generally acceptable methods of determining whether or not a key exists in a std::map:

map.find(key) != map.end()
map.count(key) > 0

Is one more efficient than the other? Specifically, the concept of count() could be interpreted to mean that the method will iterate over every key, tallying a total count (and because of the definition of std::map, that total count will always be 0 or 1). Is count() guaranteed to "stop" after a match, operating at the same complexity as a find()?

Milan
  • 1,743
  • 2
  • 13
  • 36
dolphy
  • 6,218
  • 4
  • 24
  • 32
  • 2
    `count` can only be `0` or `1` for an `std::map`. The complexity is the same. Note that you don't need the `> 0` comparison. – juanchopanza Aug 25 '14 at 16:31
  • the return of count can only be 0 or 1 (for std::map), but that is not the same as saying that the underlying implementation will guarantee that this is done efficiently – dolphy Aug 25 '14 at 16:34
  • The logarithmic complexity is a good indicator that the implementation is efficient. – juanchopanza Aug 25 '14 at 16:36

3 Answers3

76

Since a map can only have at most one key, count will essentially stop after one element has been found. However, in view of more general containers such as multimaps and multisets, find is strictly better if you only care whether some element with this key exists, since it can really stop once the first matching element has been found.

In general, both count and find will use the container-specific lookup methods (tree traversal or hash table lookup), which are always fairly efficient. It's just that count has to continue iterating until the end of the equal-range, whereas find does not. Moreover, your code should document intent, so if you want to find something, use find.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Thank you for the answer, although I want to be clear on your first sentence. Is it that count *should* stop after one element has been found, or that count *will* stop after one element has been found? In other words, is it guaranteed for std::map? – dolphy Aug 25 '14 at 16:37
  • 2
    @dolphy: As I tried to say, the map uses its internal data structure for the lookup, so for a given key it will efficiently find the range of all elements with that key (e.g. binary search in a tree), and for `count` it will return the length of that range. – Kerrek SB Aug 25 '14 at 17:02
  • 1
    Now, in the C++20, you can use `std::map::contains` to check is key is present in the map. – Raffallo Oct 19 '21 at 11:42
20

According to the source code, I suggest to use find. See the source code.

In GCC, the code is following (stl_map.h):

    const_iterator
    find(const key_type& __x) const
    { return _M_t.find(__x); }

    size_type                                                                              
    count(const key_type& __x) const                                                       
    { return _M_t.find(__x) == _M_t.end() ? 0 : 1; }  

In Visual Studio on the windows platform, the code are following (xtree):

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

    //....

    const_iterator lower_bound(const key_type& _Keyval) const
    {   // find leftmost node not less than _Keyval in nonmutable tree
        return (const_iterator(_Lbound(_Keyval), this));
    }

    //....

    _Nodeptr _Lbound(const key_type& _Keyval) const
    {   // find leftmost node not less than _Keyval
        _Nodeptr _Pnode = _Root();
        _Nodeptr _Wherenode = this->_Myhead;    // end() if search fails

        while (!this->_Isnil(_Pnode))
            if (_DEBUG_LT_PRED(this->_Getcomp(), this->_Key(_Pnode), _Keyval))
                _Pnode = this->_Right(_Pnode);  // descend right subtree
            else
                {   // _Pnode not less than _Keyval, remember it
                _Wherenode = _Pnode;
                _Pnode = this->_Left(_Pnode);   // descend left subtree
                }

        return (_Wherenode);    // return best remembered candidate
    }

    //..........................................
    //..........................................

    size_type count(const key_type& _Keyval) const
    {   // count all elements that match _Keyval
        _Paircc _Ans = equal_range(_Keyval);
        size_type _Num = 0;
        _Distance(_Ans.first, _Ans.second, _Num);
        return (_Num);
    }

    //....

    _Pairii equal_range(const key_type& _Keyval) const
    {   // find range equivalent to _Keyval in nonmutable tree
        return (_Eqrange(_Keyval));
    }

    //....

    _Paircc _Eqrange(const key_type& _Keyval) const
    {   // find leftmost node not less than _Keyval
        _Nodeptr _Pnode = _Root();
        _Nodeptr _Lonode = this->_Myhead;   // end() if search fails
        _Nodeptr _Hinode = this->_Myhead;   // end() if search fails

        while (!this->_Isnil(_Pnode))
            if (_DEBUG_LT_PRED(this->_Getcomp(), this->_Key(_Pnode), _Keyval))
                _Pnode = this->_Right(_Pnode);  // descend right subtree
            else
                {   // _Pnode not less than _Keyval, remember it
                if (this->_Isnil(_Hinode)
                        && _DEBUG_LT_PRED(this->_Getcomp(), _Keyval,
                        this->_Key(_Pnode)))
                    _Hinode = _Pnode;   // _Pnode greater, remember it
                _Lonode = _Pnode;
                _Pnode = this->_Left(_Pnode);   // descend left subtree
                }

        _Pnode = this->_Isnil(_Hinode) ? _Root()
            : this->_Left(_Hinode); // continue scan for upper bound
        while (!this->_Isnil(_Pnode))
            if (_DEBUG_LT_PRED(this->_Getcomp(), _Keyval, this->_Key(_Pnode)))
                {   // _Pnode greater than _Keyval, remember it
                _Hinode = _Pnode;
                _Pnode = this->_Left(_Pnode);   // descend left subtree
                }
            else
                _Pnode = this->_Right(_Pnode);  // descend right subtree

        const_iterator _First = const_iterator(_Lonode, this);
        const_iterator _Last = const_iterator(_Hinode, this);
        return (_Paircc(_First, _Last));
    }
Bright Chen
  • 309
  • 3
  • 4
  • 3
    What is the argument to use find? The GCC example shows that count is implemented in terms of find, so why should I prefer find in that case? – user2445507 Sep 09 '20 at 00:31
8

If you just want to find whether the key exists or not, and don't care about the value, it is better to use map::count as it returns only an integer. map::find returns an iterator, thus by using count, you will save the construction of an iterator.

Sagar Jha
  • 1,068
  • 4
  • 14
  • 24
  • 14
    As you can see in source code (another answer) - implementation of "count" constructs more iterators internally comparing to implementation of "find". – Ezh Mar 14 '18 at 10:27
  • @Ezh In that answer (I guess you mean Bright Chen's), for GCC the iterators used are the same, not more. According to the code, `if(m.count(i))` does the same as `if(m.find(i) != m.end())`. – xamid Jan 06 '21 at 03:54