Как извлечь все ключи (или значения) из std :: map и поместить их в вектор? - PullRequest
206 голосов
/ 21 сентября 2008

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

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 не включает функцию-член для нас.)

Ответы [ 16 ]

152 голосов
/ 21 сентября 2008

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

Я не уверен, что ваша цель - вставить ключи в вектор или напечатать их для 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, потому что там меньше набирается текста, и она очень четко говорит о том, что она делает.

134 голосов
/ 14 марта 2012
//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);
57 голосов
/ 05 марта 2012

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

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

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

42 голосов
/ 08 мая 2010

C ++ 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;});
11 голосов
/ 16 сентября 2016

@ DanDan ответ, используя C ++ 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;
}); 

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

10 голосов
/ 21 сентября 2008

SGI STL имеет расширение под названием select1st. Жаль, что это не в стандартном STL!

9 голосов
/ 21 сентября 2008

Я думаю, что 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 может быть действительно чистым в других случаях.

7 голосов
/ 21 сентября 2008

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

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
}
6 голосов
/ 21 сентября 2008

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

5 голосов
/ 21 сентября 2008

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

...