unordered_multimap - iterating the result of find(

2019-01-23 05:52发布

问题:

The multimap in C++ seems to work really odd, i would like to know why

#include <iostream>
#include <unordered_map>

using namespace std;

typedef unordered_multimap<char,int> MyMap;

int main(int argc, char **argv)
{
    MyMap map;
    map.insert(MyMap::value_type('a', 1));
    map.insert(MyMap::value_type('b', 2));
    map.insert(MyMap::value_type('c', 3));
    map.insert(MyMap::value_type('d', 4));
    map.insert(MyMap::value_type('a', 7));
    map.insert(MyMap::value_type('b', 18));

    for(auto it = map.begin(); it != map.end(); it++) {
        cout << it->first << '\t';
        cout << it->second << endl;
    }

    cout << "all values to a" << endl;
    for(auto it = map.find('a'); it != map.end(); it++) {
        cout << it->first << '\t' << it->second << endl;
    }

}

this is the output:

c   3
d   4
a   1
a   7
b   2
b   18
all values to a
a   1
a   7
b   2
b   18

why does the output still contain anything with b as the key when I am explicitly asking for 'a'? Is this a compiler or stl bug?

回答1:

find, as implemented, returns an iterator for the first element which matches the key in the multimap (as with any other map). You're likely looking for equal_range:

// Finds a range containing all elements whose key is k.
// pair<iterator, iterator> equal_range(const key_type& k)
auto its = map.equal_range('a');
for (auto it = its.first; it != its.second; ++it) {
    cout << it->first << '\t' << it->second << endl;
}


回答2:

That's not a bug, it is by design. find returns an iterator to one of the matching elements, that's all. You'll iterate to the end of the map with your construct.

You need to use multimap::equal_range to do what you are after.



回答3:

There is an Example in www.cplusplus.com , about How to use equal_range method to get all elements having the same key.

// unordered_multimap::equal_range
#include <iostream>
#include <string>
#include <unordered_map>
#include <algorithm>

typedef std::unordered_multimap<std::string,std::string> stringmap;

int main ()
{
  stringmap myumm = {
     {"orange","FL"},
     {"strawberry","LA"},
     {"strawberry","OK"},
     {"pumpkin","NH"}
  };

  std::cout << "Entries with strawberry:";
  auto range = myumm.equal_range("strawberry");
  for_each (
    range.first,
    range.second,
    [](stringmap::value_type& x){std::cout << " " << x.second;}
  );

  return 0;
}

Please reference the link : http://www.cplusplus.com/reference/unordered_map/unordered_multimap/equal_range/



回答4:

It would seem that you get an iterator into the full "list" of pairs, starting at the first pair with 'a' as it's key. So when you iterate to the end, naturally you will get everything beyond 'a' as well. If you sought for 'c', you would probably iterate through the entire "list" doing what you do there. Perhaps you should iterate to "it != map.end() && it->first == 'a'" if you want all the a's.