在C ++映射中迭代键

有没有一种方法来遍历键,而不是一对C ++地图?

如果你真的需要隐藏“真正的”迭代器返回的值(例如,因为你想用你的key-iterator与标准algorithm,所以他们在键而不是对操作),然后看看Boost的transform_iterator 。

[提示:查看新类的Boost文档时,首先阅读“示例”。 然后,你有一个运动的机会,弄清楚其他人在说什么:-)]

地图是关联容器。 因此,迭代器是一对key,val。 如果您只需要密钥,则可以忽略该对中的值部分。

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

编辑::如果你想只公开外面的钥匙,那么你可以将地图转换为vector或键和揭露。

使用C ++ 11,迭代语法很简单。 你仍然迭代对,但只是访问关键是很容易的。

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

没有提升

你可以通过简单地扩展该地图的STL迭代器来完成。 例如,string到整数的映射:

 #include <map> typedef map<string, int> 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; } }; 

您也可以在模板中执行此扩展 ,以获得更一般的解决scheme。

除了迭代映射的begin()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()); 

你正在寻找map_keys ,你可以写这样的东西

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

在Ian提到的更通用的模板解决scheme下面

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

所有学分去伊恩…谢谢伊恩。

这里有一个如何使用Boost的transform_iterator来做的例子

 #include <iostream> #include <map> #include <iterator> #include "boost/iterator/transform_iterator.hpp" using std::map; typedef std::string Key; typedef std::string Val; map<Key,Val>::key_type get_key(map<Key,Val>::value_type aPair) { return aPair.first; } typedef map<Key,Val>::key_type (*get_key_t)(map<Key,Val>::value_type); typedef map<Key,Val>::iterator map_iterator; typedef boost::transform_iterator<get_key_t, map_iterator> mapkey_iterator; int main() { map<Key,Val> 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 << i->first << " " << i->second << std::endl; } // iterate over the keys using the transformed iterators mapkey_iterator keybegin(m.begin(), get_key); mapkey_iterator keyend(m.end(), get_key); for(mapkey_iterator i = keybegin; i != keyend; i++) { std::cout << *i << std::endl; } } 

你想这样做?

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

如果你需要一个只返回键的迭代器,你需要在你自己的类中包装map的迭代器,以提供所需的接口。 您可以像这里一样从头开始声明一个新的迭代器类,使用现有的帮助器结构。 这个答案显示了如何使用Boost的transform_iterator将迭代器包装成只返回值/键的迭代器。

你可以

  • 创build一个自定义迭代器类,聚合std::map<K,V>::iterator
  • 使用你的map.begin() std::transform来将map.end()与一个boost::bind( &pair::second, _1 )函数
  • 在迭代for循环时,忽略->second成员。

当不需要明确的beginend ,即对于范围循环,可以通过关键字(第一示例)或值(第二示例)的循环

 #include <boost/range/adaptors.hpp> map<Key, Value> m; for (auto k : boost::adaptors::keys(m)) cout << k << endl; for (auto v : boost::adaptors::values(m)) cout << v << endl; 

我知道这不能回答你的问题,但你可能想要看的一个选项是有两个向量相同的索引是“链接”的信息..

所以在..

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

如果你想通过名字来计算名字,你只需要快速地循环vName.size(),并且当你发现它是你正在寻找的vNameCount的索引时。

当然,这可能不会给你所有的地图function,取决于可能或可能不会更好,但如果你不知道密钥,可能会更容易,而不应该添加太多的处理。

只要记住,当你从一个添加/删除,你必须从另一个或事情会变得疯狂嘿:P

这个答案就像是rodrigob的,除了没有BOOST_FOREACH 。 你可以用c ++的范围代替。

 #include <map> #include <boost/range/adaptor/map.hpp> #include <iostream> template <typename K, typename V> void printKeys(std::map<K,V> map){ for(auto key : map | boost::adaptors::map_keys){ std::cout << key << std::endl; } } 

使用C ++ 17,您可以在基于范围的for循环中使用结构化的绑定 :

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

不幸的是,C ++ 17标准要求你声明valuevariables,即使你不使用它( std::ignore ,因为std::tie(..)不起作用,请参阅这个讨论 )。 因此,你的编译器会警告你未使用的valuevariables!

关于未使用的variables的编译时警告对于我的任何生产代码来说都是不可行的。 所以这只是一个假设的完整性的例子。

没有Boost,你可以这样做。 如果你可以写一个转换运算符而不是getKeyIterator(),那就好了,但是我不能编译它。

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

对于后人,因为我试图find一种方法来创build一个范围,另一种方法是使用boost :: adapters :: transform

这是一个小例子:

 #include <boost/range/adaptor/transformed.hpp> #include <iostream> #include <map> int main(int argc, const char* argv[]) { std::map<int, int> m; m[0] = 1; m[2] = 3; m[42] = 0; auto key_range = boost::adaptors::transform( m, [](std::map<int, int>::value_type const& t) { return t.first; } ); for (auto&& key : key_range) std::cout << key << ' '; std::cout << '\n'; return 0; } 

如果要迭代这些值, t.second在lambda中使用t.second

这里有很多很好的答案,下面是使用其中的几个方法,可以让你写这个:

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

如果这是你一直想要的,那么这里是MapKeys()的代码:

 template <class MapType> 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 <class MapType> MapKeyIterator<MapType> MapKeys(MapType& m) { return MapKeyIterator<MapType>(m); }