Как извлечь все ключи (или значения) из std:: map и поместить их в вектор?

Это один из возможных способов выхода:

struct RetrieveKey
{
    template <typename T>
    typename T::first_type operator()(T keyValuePair) const
    {
        return keyValuePair.first;
    }
};

map<int, int> m;
vector<int> keys;

// Retrieve all keys
transform(m.begin(), m.end(), back_inserter(keys), RetrieveKey());

// Dump all keys
copy(keys.begin(), keys.end(), ostream_iterator<int>(cout, "\n"));

Конечно, мы также можем извлечь все значения из карты, указав другой функтор RetrieveValues ​​.

Есть ли другой способ добиться этого легко? (Мне всегда интересно, почему std:: map не включает в себя функцию-член для нас.)

Ответ 1

В то время как ваше решение должно работать, его может быть трудно читать в зависимости от уровня навыков ваших коллег-программистов. Кроме того, он перемещает функциональность в стороне от сайта вызова. Что может сделать обслуживание немного сложнее.

Я не уверен, что ваша цель - получить ключи в вектор или распечатать их до cout, чтобы я делал то и другое. Вы можете попробовать что-то вроде этого:

map<int, int> m;
vector<int> v;
for(map<int,int>::iterator it = m.begin(); it != m.end(); ++it) {
  v.push_back(it->first);
  cout << it->first << "\n";
}

Или даже проще, если вы используете Boost:

map<int,int> m;
pair<int,int> me; // what a map<int, int> is made of
vector<int> v;
BOOST_FOREACH(me, m) {
  v.push_back(me.first);
  cout << me.first << "\n";
}

Лично мне нравится версия BOOST_FOREACH, потому что есть меньше набрав, и она очень ясна в том, что она делает.

Ответ 2

//c++0x too
std::map<int,int> mapints;
std::vector<int> vints;
vints.reserve(mapints.size());
for(auto const& imap: mapints)
    vints.push_back(imap.first);

Ответ 3

Для этой цели существует адаптер диапазона дальности:

vector<int> keys;
// Retrieve all keys
boost::copy(m | boost::adaptors::map_keys, std::back_inserter(keys));

Существует аналогичный адаптер диапазона map_values ​​для извлечения значений.

Ответ 4

С++ 0x дал нам еще одно превосходное решение:

std::vector<int> keys;

std::transform(
    m_Inputs.begin(),
    m_Inputs.end(),
    std::back_inserter(keys),
    [](const std::map<int,int>::value_type &pair){return pair.first;});

Ответ 5

SGI STL имеет расширение, называемое select1st. Слишком плохо это не в стандартном STL!

Ответ 6

@Ответ DanDan, используя С++ 11:

using namespace std;
vector<int> keys;

transform(begin(map_in), end(map_in), back_inserter(keys), 
            [](decltype(map_in)::value_type const& pair) {
    return pair.first;
}); 

и используя С++ 14 (как отмечено @ivan.ukr), мы можем заменить decltype(map_in)::value_type на auto.

Ответ 7

Я думаю, что представленный выше BOOST_FOREACH хорош и чист, однако есть и другой вариант использования BOOST.

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>

std::map<int, int> m;
std::vector<int> keys;

using namespace boost::lambda;

transform(      m.begin(), 
                m.end(), 
                back_inserter(keys), 
                bind( &std::map<int,int>::value_type::first, _1 ) 
          );

copy( keys.begin(), keys.end(), std::ostream_iterator<int>(std::cout, "\n") );

Лично я не думаю, что этот подход так же чист, как подход BOOST_FOREACH в этом случае, но boost:: lambda может быть действительно чистым в других случаях.

Ответ 8

Ваше решение в порядке, но вы можете использовать итератор для этого:

std::map<int, int> m;
m.insert(std::pair<int, int>(3, 4));
m.insert(std::pair<int, int>(5, 6));
for(std::map<int, int>::const_iterator it = m.begin(); it != m.end(); it++)
{
    int key = it->first;
    int value = it->second;
    //Do something
}

Ответ 9

Кроме того, если у вас есть Boost, используйте transform_iterator, чтобы избежать временного копирования ключей.

Ответ 10

Вы можете использовать универсальный boost :: transform_iterator. Transform_iterator позволяет вам преобразовывать повторяющиеся значения, например, в нашем случае, когда вы хотите иметь дело только с ключами, а не со значениями. См. Http://www.boost.org/doc/libs/1_36_0/libs/iterator/doc/transform_iterator.html#example

Ответ 11

Лучшим решением non-sgi, non-boost STL является расширение map:: итератора следующим образом:

template<class map_type>
class key_iterator : public map_type::iterator
{
public:
    typedef typename map_type::iterator map_iterator;
    typedef typename map_iterator::value_type::first_type key_type;

    key_iterator(const map_iterator& other) : map_type::iterator(other) {} ;

    key_type& operator *()
    {
        return map_type::iterator::operator*().first;
    }
};

// helpers to create iterators easier:
template<class map_type>
key_iterator<map_type> key_begin(map_type& m)
{
    return key_iterator<map_type>(m.begin());
}
template<class map_type>
key_iterator<map_type> key_end(map_type& m)
{
    return key_iterator<map_type>(m.end());
}

а затем используйте их так:

        map<string,int> test;
        test["one"] = 1;
        test["two"] = 2;

        vector<string> keys;

//      // method one
//      key_iterator<map<string,int> > kb(test.begin());
//      key_iterator<map<string,int> > ke(test.end());
//      keys.insert(keys.begin(), kb, ke);

//      // method two
//      keys.insert(keys.begin(),
//           key_iterator<map<string,int> >(test.begin()),
//           key_iterator<map<string,int> >(test.end()));

        // method three (with helpers)
        keys.insert(keys.begin(), key_begin(test), key_end(test));

        string one = keys[0];

Ответ 12

Бит С++ 11 принимает:

std::map<uint32_t, uint32_t> items;
std::vector<uint32_t> itemKeys;
for (auto & kvp : items)
{
    itemKeys.emplace_back(kvp.first);
    std::cout << kvp.first << std::endl;
}

Ответ 13

Вот хороший шаблон функции с использованием С++ 11 magic, работающий как для std:: map, std:: unordered_map:

template<template <typename...> class MAP, class KEY, class VALUE>
std::vector<KEY>
keys(const MAP<KEY, VALUE>& map)
{
    std::vector<KEY> result;
    result.reserve(map.size());
    for(const auto& it : map){
        result.emplace_back(it.first);
    }
    return result;
}

Посмотрите здесь: http://ideone.com/lYBzpL

Ответ 14

Немного похоже на один из примеров, упрощенный с точки зрения использования std::map.

template<class KEY, class VALUE>
std::vector<KEY> getKeys(const std::map<KEY, VALUE>& map)
{
    std::vector<KEY> keys(map.size());
    for (const auto& it : map)
        keys.push_back(it.first);
    return keys;
}

Используйте как это:

auto keys = getKeys(yourMap);

Ответ 15

Основано на решении @rusty-parks, но в С++ 17:

std::map<uint32_t, uint32_t> items;
std::vector<uint32_t> itemKeys;
for (auto const& [key, std:ignore] : items) {
  itemKeys.emplace_back(key);
}

Ответ 16

(Мне всегда интересно, почему std:: map не включает в себя функцию-член для нас.)

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

Также не сразу понятно, почему это так полезно.