迭代C ++映射中的键

时间:2009-09-18 10:45:04

标签: c++ stl

有没有办法迭代键,而不是C ++映射对?

20 个答案:

答案 0 :(得分:100)

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;
}

修改: 如果您只想将键暴露给外部,那么您可以将地图转换为矢量或键并公开。

答案 1 :(得分:75)

使用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";
    }
}

答案 2 :(得分:68)

如果你真的需要隐藏“真正的”迭代器返回的值(例如,因为你想要使用带有标准算法的key-iterator,以便它们对键而不是对子进行操作),那么看看Boost的transform_iterator

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

答案 3 :(得分:33)

没有提升

您可以通过简单地扩展该映射的STL迭代器来完成此操作。例如,字符串到ints的映射:

#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; }
};

您也可以perform this extension in a template获得更一般的解决方案。

你使用你的迭代器就像你使用列表迭代器一样,除非你迭代地图的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());

答案 4 :(得分:15)

使用C ++ 17 ,您可以在structured binding内使用range-based for loop(相应地调整John H.'s answer):

#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(..)那样使用this discussion工作,见https://github.com/nunit/nunit.xamarin)。

因此,某些编译器可能会警告您未使用的value变量!关于未使用的变量的编译时警告对于我认为的任何生产代码都是不可行的。因此,这可能不适用于某些编译器版本。

答案 5 :(得分:11)

下面是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。

答案 6 :(得分:10)

您正在寻找map_keys,您可以使用它来编写

之类的内容
BOOST_FOREACH(const key_t key, the_map | boost::adaptors::map_keys)
{
  // do something with key
}

答案 7 :(得分:4)

当不需要显式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;

答案 8 :(得分:4)

以下是使用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;
  }
}

答案 9 :(得分:3)

你想这样做吗?

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

答案 10 :(得分:3)

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

答案 11 :(得分:2)

除了没有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;
     }
}

答案 12 :(得分:2)

你可以

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

答案 13 :(得分:1)

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

所以... ..

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

std::vector<int> vNameCount;

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

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

请记住,当您添加/删除其中一个时,您必须从另一个中执行此操作或者事情会变得疯狂嘿嘿:P

答案 14 :(得分:1)

使用 C++20,我们可以访问 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

答案 15 :(得分:0)

如果没有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());
    }
}

答案 16 :(得分:0)

对于后代,由于我试图找到创建范围的方法,另一种方法是使用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;
}

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

答案 17 :(得分:0)

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

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);
}

答案 18 :(得分:0)

我已经采用了伊恩(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;
    }
};

答案 19 :(得分:0)

无需BOOST,直接使用键和值

for(auto const& [key, value]: m_map)
    {
    std::cout<<" key="<<key;
    std::cout<<" value="<<value<<std::endl;
    }