Итерации ключей на карте С++

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

Ответ 1

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

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

Ответ 2

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

EDIT:: Если вы хотите выставить только внешние ключи, вы можете преобразовать карту в вектор или ключи и выставить.

Ответ 3

С С++ 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";
    }
}

Ответ 4

Без увеличения

Вы можете сделать это, просто расширив итератор 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; }
};

Вы также можете выполнить это расширение в шаблоне для более общего решения.

Вы используете свой итератор точно так же, как если бы вы использовали итератор списка, за исключением того, что вы выполняете итерацию по карте 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());

Ответ 5

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

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

Ответ 6

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

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

Все кредиты идут к Яну... Спасибо Яну.

Ответ 7

Вот пример того, как это сделать, используя 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 (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;
  }
}

Ответ 8

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

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

Ответ 9

Если вам нужен итератор, который просто возвращает ключи, вам необходимо обернуть итератор карты в свой класс, который предоставляет желаемый интерфейс. Вы можете объявить новый класс итератора с нуля, как здесь, использовать существующие вспомогательные конструкции. Этот ответ показывает, как использовать Boost transform_iterator, чтобы обернуть итератор в один который возвращает значения/ключи.

Ответ 10

Вы могли

  • создать собственный класс итератора, объединив std::map<K,V>::iterator
  • используйте std::transform вашего map.begin() до map.end() с функтором boost::bind( &pair::second, _1 )
  • просто игнорирует член ->second, итерации с помощью цикла for.

Ответ 11

Если явные 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;

Ответ 12

С С++ 17 вы можете использовать структурированное привязку внутри диапазон для цикла (адаптация 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';
    }
}

К сожалению, для стандарта С++ 17 требуется объявить переменную value, даже если вы ее не используете (std::ignore, как было бы использовано для std::tie(..), не работает, см. обсуждение). Поэтому ваш компилятор предупредит вас о неиспользуемой переменной value!

Предупреждения о компиляции в отношении неиспользуемых переменных - это не-хот для любого производственного кода. Так что это всего лишь гипотетический пример полноты.

Ответ 13

Я знаю, что это не отвечает на ваш вопрос, но один из вариантов, который вы можете посмотреть, - это просто наличие двух векторов с одним и тем же индексом, который является "связанной" информацией.

Так в..

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

std::vector<int> vNameCount;

если вы хотите, чтобы количество имен по имени вы просто делали для цикла по vName.size(), и когда вы обнаружите, что это индекс для vNameCount, который вы ищете.

Уверен, что это не может дать вам всю функциональность карты, и в зависимости может или не может быть лучше, но может быть проще, если вы не знаете ключи и не должны добавлять слишком много обработки.

Просто помните, когда вы добавляете/удаляете один из них, вы должны делать это от другого, или все будет сумасшедшим хе: P

Ответ 14

Этот ответ похож на rodrigob, кроме BOOST_FOREACH. Вместо этого вы можете использовать диапазон С++.

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

Ответ 15

Без 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

Для потомков, и поскольку я пытался найти способ создания диапазона, альтернативой является использование повышение:: адаптеры:: преобразование

Вот небольшой пример:

#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 в лямбда.

Ответ 17

Много хороших ответов здесь, ниже - это подход, использующий пару из них, который позволяет вам написать это:

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