有没有一种方法可以迭代键,而不是 C + + 映射的对?
Map 是关联容器。因此,迭代器是一对键,val。如果只需要键,则可以忽略对中的值部分。
for(std::map<Key,Val>::iterator iter = myMap.begin(); iter != myMap.end(); ++iter) { Key k = iter->first; //ignore value //Value v = iter->second; }
编辑: 如果您只想向外部公开键,那么您可以将映射转换为向量或键并公开。
你想这么做吗?
std::map<type,type>::iterator iter = myMap.begin(); std::map<type,type>::iterator endIter = myMap.end(); for(; iter != endIter; ++iter) { type key = iter->first; ..... }
如果您真的需要隐藏“真正的”迭代器返回的值(例如,因为您想在标准算法中使用键迭代器,以便它们操作键而不是对) ,那么请看 Boost 的 转换迭代器。
[提示: 当查看新类的 Boost 文档时,首先阅读结尾的“示例”。然后,你就有机会搞清楚其余部分究竟在谈论什么:
你可以的
std::map<K,V>::iterator
map.begin()
std::transform
map.end()
boost::bind( &pair::second, _1 )
for
->second
如果您需要一个只返回键的迭代器,那么您需要将 map 的迭代器包装到您自己的类中,该类提供所需的接口。您可以从头声明一个新的迭代器类,比如使用现有的帮助器构造的 给你。这个答案展示了如何使用 Boost 的 transform_iterator将迭代器包装在一个只返回值/键的迭代器中。
transform_iterator
我知道这并不能回答你的问题,但是你可能想看到的一个选项是,只有两个具有相同索引的向量被“链接”信息。.
所以..。
std::vector<std::string> vName; std::vector<int> vNameCount;
如果您想要按名称计数,只需在 vName.size ()上执行快速 for 循环,当您找到它时,它就是您正在寻找的 vNameCount 的索引。
当然,这可能不会给你所有的功能的地图,并取决于可能或可能不是更好,但它可能会更容易,如果你不知道的关键,不应该添加太多的处理。
只要记住,当你添加/删除一个你必须做它从另一个否则事情会变得疯狂嘿: P
下面是一个如何使用 Boost 的 转换迭代器实现的示例
#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; } }
你正在寻找 Map _ keys,用它你可以写东西像
BOOST_FOREACH(const key_t key, the_map | boost::adaptors::map_keys) { // do something with key }
没有 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()); } }
您可以通过简单地扩展该映射的 STL 迭代器来实现这一点。例如,字符串到 int 的映射:
#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; } };
您也可以使用 在模板中执行此扩展,以获得更通用的解决方案。
您使用迭代器的方式与使用列表迭代器的方式完全一样,只不过是在映射的 begin()和 end()上进行迭代。
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());
使用 C + + 11,迭代语法很简单,仍然可以对对进行迭代,但是只需要访问键就很容易了。
#include <iostream> #include <map> int 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"; } }
这个答案和 rodrigob 的一样,只是没有 BOOST_FOREACH。你可以用 c + + 的范围来代替。
BOOST_FOREACH
#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; } }
在伊恩提到的更一般的模板解决方案下面..。
#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; } };
所有学分归 Ian... 谢谢 Ian。
对于子孙后代来说,由于我试图找到一种方法来创建一个范围,另一种选择是使用 适配器: : 转换
举个小例子:
#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; }
如果希望对值进行迭代,请在 lambda 中使用 t.second。
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); }
当不需要显式的 begin和 end时,即对于范围循环,可以使用
begin
end
#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;
使用 C + + 17 ,你可以在 基于范围的循环中使用 结构化绑定结构化绑定(相应地调整 John H 的回答) :
#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标准要求您声明 value变量,即使您没有使用它(std::ignore作为 std::tie(..)的一种使用方法是不起作用的,请参阅 这个讨论)。
value
std::ignore
std::tie(..)
因此,一些编译器可能会对未使用的 value变量发出警告!在我看来,关于未使用变量的编译时警告对于任何生产代码都是不可行的。因此,这可能不适用于某些编译器版本。
我已经采用了伊恩的回答与所有地图类型的工作和固定返回一个 operator*的参考
operator*
template<typename T> class MapKeyIterator : public T { public: MapKeyIterator() : T() {} MapKeyIterator(T iter) : T(iter) {} auto* operator->() { return &(T::operator->()->first); } auto& operator*() { return T::operator*().first; } };
for(auto const& [key, value]: m_map) { std::cout<<" key="<<key; std::cout<<" value="<<value<<std::endl; }
使用 C + + 20,我们可以访问 ranges库,它有一个很好的解决方案: std::views::keys
ranges
std::views::keys
#include <ranges> //... std::map<int, int> myMap = \{\{1,2},{3,4},{5,6}}; auto keys = std::views::keys(myMap); for(auto key : keys) { std::cout << key << std::endl; }
自己试试看: https://godbolt.org/z/heeWv4Gh6