Answers:
如果您确实需要隐藏“真实”迭代器返回的值(例如,因为您希望将key-iterator与标准算法一起使用,以便它们对密钥进行操作而不是对操作),那么请看一下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;
}
编辑::如果您只想将键公开到外部,则可以将地图转换为矢量或键并公开。
const Key& k(iter->first);
std::vector<Key> v(myMap.begin(), myMap.end())
。
您可以通过简单地扩展该映射的STL迭代器来实现。例如,字符串到整数的映射:
#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()
。
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());
template<typename C> class key_iterator : public C::iterator
等等
使用C ++ 17,您可以在基于范围的for循环内使用结构化绑定(相应地适应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';
}
}
不幸的是value
,即使您没有使用C ++ 17标准,您也需要声明该变量(std::ignore
因为使用该变量将std::tie(..)
不起作用,请参阅此讨论)。
因此,某些编译器可能会警告您有关未使用的value
变量!在我看来,关于未使用变量的编译时警告对于任何生产代码都是行不通的。因此,这可能不适用于某些编译器版本。
for ([[maybe_unused]] const auto &[key, v_not_used] : my_map) { use(key); }
在Ian提到的更通用的模板化解决方案下面...
#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。
您正在寻找map_keys,您可以编写类似
BOOST_FOREACH(const key_t key, the_map | boost::adaptors::map_keys)
{
// do something with key
}
BOOST_FOREACH(const key_t& key, ...
这是如何使用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;
}
}
当不需要显式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;
你想这样做吗?
std::map<type,type>::iterator iter = myMap.begin();
std::map<type,type>::iterator iter = myMap.end();
for(; iter != endIter; ++iter)
{
type key = iter->first;
.....
}
如果您需要一个仅返回键的迭代器,则需要将地图的迭代器包装在您自己的提供所需接口的类中。您可以像这里一样从头开始声明一个使用现有帮助程序构造的新迭代器类。此答案显示了如何使用Boost transform_iterator
来将迭代器包装为仅返回值/键的迭代器。
没有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());
}
}
对于后代,由于我试图找到一种创建范围的方法,因此可以选择使用boost :: adaptors :: 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中使用。
这里有很多不错的答案,下面是使用其中几个的一种方法,您可以这样编写:
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);
}
我采用了伊恩(Ian)的答案来处理所有地图类型,并固定返回了 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;
}
};
我知道这并不能回答您的问题,但是您可能要看的一个选择就是让两个向量的“索引”信息具有相同的索引。
等等
std::vector<std::string> vName;
std::vector<int> vNameCount;
如果要按名称对名称进行计数,则只需在vName.size()上进行快速for循环即可,当您找到它时,这就是您要查找的vNameCount的索引。
当然,这可能不会给您提供地图的所有功能,并且视情况而定可能会更好,但如果您不知道键,并且不应该添加过多的处理,可能会更容易。
只要记住,当您从一个添加或删除一个时,您必须从另一个添加或删除它,否则事情会变得很疯狂。