迭代 C++ 映射中的键
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1443793/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Iterate keys in a C++ map
提问by Bogdan Balan
Is there a way to iterate over the keys, not the pairs of a C++ map?
有没有办法迭代键,而不是 C++ 映射对?
采纳答案by Steve Jessop
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.
如果您确实需要隐藏“真实”迭代器返回的值(例如,因为您想将密钥迭代器与标准算法一起使用,以便它们对键而不是对进行操作),那么请查看 Boost 的变换迭代器。
[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 :-)]
[提示:查看新类的 Boost 文档时,请先阅读末尾的“示例”。然后,您就有机会弄清楚其余部分到底在说什么:-)]
回答by aJ.
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.
地图是关联容器。因此,迭代器是一对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;
}
EDIT:: In case you want to expose only the keys to outside then you can convert the map to vector or keys and expose.
编辑::如果您只想将键公开给外部,那么您可以将地图转换为向量或键并公开。
回答by John H.
With C++11 the iteration syntax is simple. You still iterate over pairs, but accessing just the key is easy.
使用 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";
}
}
回答by Ian
Without Boost
没有升压
You can do this by simply extending the STL iterator for that map. For example, a mapping of strings to ints:
您可以通过简单地扩展该映射的 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; }
};
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()
.
您可以像使用列表迭代器一样使用您的迭代器,不同之处在于您要迭代地图的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());
回答by Elmar
With C++17you can use a structured bindinginside a range-based for loop(adapting John H.'s answeraccordingly):
使用 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';
}
}
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).
不幸的是,C++17 标准要求您声明该value
变量,即使您没有使用它(std::ignore
因为它std::tie(..)
不起作用,请参阅此讨论)。
Some compilers may therefore 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 may not be applicable for certain compiler versions.
因此,某些编译器可能会警告您未使用的value
变量!在我看来,关于未使用变量的编译时警告对于任何生产代码都是不可行的。因此,这可能不适用于某些编译器版本。
回答by degski
Below the more general templated solution to which Ian referred...
在 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; }
};
All credits go to Ian... Thanks Ian.
所有学分都归伊恩所有……谢谢伊恩。
回答by rodrigob
回答by algal
Here's an example of how to do it using Boost's transform_iterator
这是一个如何使用 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;
}
}
回答by Darko Veberic
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
当不需要显式begin
and 时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;
回答by sth
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 answershows how to use Boost's transform_iterator
to wrap the iterator in one that only returns the values/keys.
如果您需要一个只返回键的迭代器,您需要将地图的迭代器包装在您自己的提供所需接口的类中。您可以像这里一样从头开始声明一个新的迭代器类,使用现有的帮助器构造。这个答案显示了如何使用 Boosttransform_iterator
将迭代器包装在一个只返回值/键的迭代器中。