迭代 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 19:59:23  来源:igfitidea点击:

Iterate keys in a C++ map

c++stl

提问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 valuevariable, even though you're not using it (std::ignoreas 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 valuevariable! 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

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

你正在寻找map_keys,你可以用它写一些东西

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

回答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 beginand endis needed, ie for range-looping, the loop over keys (first example) or values (second example) can be obtained with

当不需要显式beginand 时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_iteratorto wrap the iterator in one that only returns the values/keys.

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