Iterate keys in a C++ map

匿名 (未验证) 提交于 2019-12-03 02:28:01

问题:

Is there a way to iterate over the keys, not the pairs of a C++ map?

回答1:

If you really need to hide the value that the "real" iterator returns (for example because you want to use your key-iterator with standard algorithms, so that they operate on the keys instead of the pairs), then take a look at Boost's transform_iterator.

[Tip: when looking at Boost documentation for a new class, read the "examples" at the end first. You then have a sporting chance of figuring out what on earth the rest of it is talking about :-)]



回答2:

map is associative container. Hence, iterator is a pair of key,val. IF you need only keys, you can ignore the value part from the pair.

for(std::map::iterator iter = myMap.begin(); iter != myMap.end(); ++iter) { Key k =  iter->first; //ignore value //Value v = iter->second; } 

EDIT:: In case you want to expose only the keys to outside then you can convert the map to vector or keys and expose.



回答3:

With C++11 the iteration syntax is simple. You still iterate over pairs, but accessing just the key is easy.

#include  #include   main() {     std::map<:string int=""> myMap;      myMap["one"] = 1;     myMap["two"] = 2;     myMap["three"] = 3;      for ( const auto &myPair : myMap ) {         std::cout 


回答4:

Without Boost

You can do this by simply extending the STL iterator for that map. For example, a mapping of strings to ints:

#include  typedef map ScoreMap; typedef ScoreMap::iterator ScoreMapIterator;  class key_iterator : public ScoreMapIterator {   public:     key_iterator() : ScoreMapIterator() {};     key_iterator(ScoreMapIterator s) : ScoreMapIterator(s) {};     string* operator->() { return (string* const)&(ScoreMapIterator::operator->()->first); }     string operator*() { return ScoreMapIterator::operator*().first; } }; 

You could also perform this extension in a template, for a more general solution.

You use your iterator exactly like you would use a list iterator, except you're iterating over the map's begin() and end().

ScoreMap m; m["jim"] = 1000; m["sally"] = 2000;  for (key_iterator s = m.begin(); s != m.end(); ++s)     printf("\n key %s", s->c_str()); 


回答5:

You are looking for map_keys, with it you can write things like

BOOST_FOREACH(const key_t key, the_map | boost::adaptors::map_keys) {   // do something with key } 


回答6:

Below the more general templated solution to which Ian referred...

#include   template using Map = std::map;  template using MapIterator = typename Map::iterator;  template class MapKeyIterator : public MapIterator {  public:      MapKeyIterator ( ) : MapIterator ( ) { };     MapKeyIterator ( MapIterator it_ ) : MapIterator ( it_ ) { };      Key *operator -> ( ) { return ( Key * const ) &( MapIterator::operator -> ( )->first ); }     Key operator * ( ) { return MapIterator::operator * ( ).first; } };  template class MapValueIterator : public MapIterator {  public:      MapValueIterator ( ) : MapIterator ( ) { };     MapValueIterator ( MapIterator it_ ) : MapIterator ( it_ ) { };      Value *operator -> ( ) { return ( Value * const ) &( MapIterator::operator -> ( )->second ); }     Value operator * ( ) { return MapIterator::operator * ( ).second; } }; 

All credits go to Ian... Thanks Ian.



回答7:

Here's an example of how to do it using Boost's transform_iterator

#include  #include  #include  #include "boost/iterator/transform_iterator.hpp"  using std::map; typedef std::string Key; typedef std::string Val;  map::key_type get_key(map::value_type aPair) {   return aPair.first; }  typedef map::key_type (*get_key_t)(map::value_type); typedef map::iterator map_iterator; typedef boost::transform_iterator mapkey_iterator;  int main() {   map m;   m["a"]="A";   m["b"]="B";   m["c"]="C";    // iterate over the map's (key,val) pairs as usual   for(map_iterator i = m.begin(); i != m.end(); i++) {     std::cout first second 


回答8:

With C++17 you can use a structured binding inside a range-based for loop (adapting John H.'s answer accordingly):

#include  #include   int main() {     std::map<:string int=""> myMap;      myMap["one"] = 1;     myMap["two"] = 2;     myMap["three"] = 3;      for ( const auto &[key, value]: myMap ) {         std::cout 

Unfortunately the C++17 standard requires you to declare the value variable, even though you're not using it (std::ignore as one would use for std::tie(..) does not work, see this discussion). Therefore, your compiler will warn you about the unused value variable!

Compile-time warnings regarding unused variables are a no-go for any production code in my mind. So this is just a hypothetical example for completeness.



回答9:

You want to do this?

std::map::iterator iter = myMap.begin(); std::map::iterator iter = myMap.end(); for(; iter != endIter; ++iter) {    type key = iter->first;      ..... } 


回答10:

If you need an iterator that just returns the keys you need to wrap map's iterator in your own class that provides the desired interface. You can declare a new iterator class from scratch like here, of use existing helper constructs. This answer shows how to use Boost's transform_iterator to wrap the iterator in one that only returns the values/keys.



回答11:

You could

  • create a custom iterator class, aggregating the std::map::iterator
  • use std::transform of your map.begin() to map.end() with a boost::bind( &pair::second, _1 ) functor
  • just ignore the ->second member while iterating with a for loop.


回答12:

When no explicit begin and end is needed, ie for range-looping, the loop over keys (first example) or values (second example) can be obtained with

#include   map m;  for (auto k : boost::adaptors::keys(m))   cout 


回答13:

I know this doesn't answer your question, but one option you may want to look at is just having two vectors with the same index being "linked" information..

So in..

std::vector<:string> vName;  std::vector vNameCount; 

if you want the count of names by name you just do your quick for loop over vName.size(), and when ya find it that is the index for vNameCount that you are looking for.

Sure this may not give ya all the functionality of the map, and depending may or may not be better, but it might be easier if ya don't know the keys, and shouldn't add too much processing.

Just remember when you add/delete from one you have to do it from the other or things will get crazy heh :P



回答14:

This answer is like rodrigob's except without the BOOST_FOREACH. You can use c++'s range based for instead.

#include  #include  #include   template  void printKeys(std::map map){      for(auto key : map | boost::adaptors::map_keys){           std::cout 


回答15:

Without Boost, you could do it like this. It would be nice if you could write a cast operator instead of getKeyIterator(), but I can't get it to compile.

#include  #include    template class key_iterator: public std::unordered_map::iterator {  public:      const K &operator*() const {         return std::unordered_map::iterator::operator*().first;     }      const K *operator->() const {         return &(**this);     } };  template key_iterator getKeyIterator(typename std::unordered_map::iterator &it) {     return *static_cast *>(&it); }  int _tmain(int argc, _TCHAR* argv[]) {     std::unordered_map<:string std::string=""> myMap;     myMap["one"]="A";     myMap["two"]="B";     myMap["three"]="C";     key_iterator<:string std::string=""> &it=getKeyIterator<:string>(myMap.begin());     for (; it!=myMap.end(); ++it) {         printf("%s\n",it->c_str());     } } 


回答16:

For posterity, and since I was trying to find a way to create a range, an alternative is to use boost::adaptors::transform

Here's a small example:

#include  #include  #include   int main(int argc, const char* argv[]) {   std::map m;   m[0]  = 1;   m[2]  = 3;   m[42] = 0;    auto key_range =     boost::adaptors::transform(       m,       [](std::map::value_type const& t)        { return t.first; }     );    for (auto&& key : key_range)     std::cout 

If you want to iterate over the values, use t.second in the lambda.



回答17:

Lots of good answers here, below is an approach using a couple of them which lets you write this:

void main() {     std::map<:string int=""> m { {"jim", 1000}, {"sally", 2000} };     for (auto key : MapKeys(m))         std::cout 

If that's what you always wanted, then here is the code for MapKeys():

template  class MapKeyIterator { public:     class iterator {     public:         iterator(typename MapType::iterator it) : it(it) {}         iterator operator++() { return ++it; }         bool operator!=(const iterator & other) { return it != other.it; }         typename MapType::key_type operator*() const { return it->first; }  // Return key part of map     private:         typename MapType::iterator it;     }; private:     MapType& map; public:     MapKeyIterator(MapType& m) : map(m) {}     iterator begin() { return iterator(map.begin()); }     iterator end() { return iterator(map.end()); } }; template  MapKeyIterator MapKeys(MapType& m) {     return MapKeyIterator(m); } 


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!