Итерация ключей в карте C ++ - PullRequest
103 голосов
/ 18 сентября 2009

Есть ли способ перебирать ключи, а не пары карт C ++?

Ответы [ 18 ]

101 голосов
/ 18 сентября 2009

карта является ассоциативным контейнером. Следовательно, итератор - это пара ключей, 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: : Если вы хотите выставить только ключи снаружи, вы можете преобразовать карту в вектор или ключи и выставить.

75 голосов
/ 29 января 2014

С 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";
    }
}
68 голосов
/ 18 сентября 2009

Если вам действительно нужно скрыть значение, которое возвращает «реальный» итератор (например, потому что вы хотите использовать итератор ключей со стандартными алгоритмами, чтобы они работали с ключами вместо пар), тогда возьмите посмотрите на Boost's transform_iterator .

[Подсказка: при просмотре документации Boost для нового класса сначала прочтите «примеры» в конце. Тогда у вас есть спортивный шанс выяснить, о чем, на самом деле, говорят остальные: -)]

34 голосов
/ 13 мая 2013

без повышения

Вы можете сделать это, просто расширив итератор 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());
16 голосов
/ 18 ноября 2017

С C ++ 17 вы можете использовать структурированное связывание внутри цикла для цикла (адаптируя ответ Джона Х. соответственно):

#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! Предупреждения во время компиляции относительно неиспользуемых переменных не нужны никакому производственному коду. Таким образом, это может быть неприменимо для определенных версий компилятора.

12 голосов
/ 08 февраля 2016

Ниже более общего шаблонного решения, на которое ссылался Ян ...

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

Все кредиты отправляются Яну ... Спасибо, Ян.

10 голосов
/ 29 августа 2012

Вы ищете map_keys , с его помощью вы можете писать такие вещи, как

BOOST_FOREACH(const key_t key, the_map | boost::adaptors::map_keys)
{
  // do something with key
}
4 голосов
/ 26 марта 2017

Когда не требуется явных 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;
4 голосов
/ 03 марта 2011

Вот пример того, как это сделать, используя Boost's 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;
  }
}
3 голосов
/ 18 сентября 2009

Вы хотите сделать это?

std::map<type,type>::iterator iter = myMap.begin();
std::map<type,type>::iterator iter = myMap.end();
for(; iter != endIter; ++iter)
{
   type key = iter->first;  
   .....
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...