Используйте STL для заполнения вектора <T>с картыключи - PullRequest
10 голосов
/ 06 октября 2011
map<T,Z> m= ...;
vector<T> v;
v.reserve(m.size);
for(map<T,Z>::iterator it=m.begin();it!=m.end();++it)
{
 v.push_back(it->first);
}

Есть ли более приятная однострочная версия, использующая некоторые функции STL?

edit: not при использовании c ++ 11!

Ответы [ 4 ]

8 голосов
/ 06 октября 2011

Портативный:

struct SelectKey {
  template <typename F, typename S>
  F operator()(const std::pair<const F, S> &x) const { return x.first; }
};

std::transform(m.cbegin(), m.cend(), std::back_inserter(v), SelectKey());

Я думаю, что некоторые реализации STL имеют нестандартное расширение, называемое select1st, что является эквивалентом SelectKey, показанным здесь. Как отметил K-Ballo в комментариях, есть также версия TR1. Мне нравится версия с явным именем, так как легче увидеть, что происходит.

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

template <typename F, typename S>
F SelectKey()(const std::pair<const F, S> &x) { return x.first; }

std::transform(m.cbegin(), m.cend(), std::back_inserter(v), SelectKey);

Если бы вы могли использовать C ++ 11 , вы могли бы использовать лямбду, в которой код выбора находится вблизи того места, где он используется:

std::transform(m.cbegin(), m.cend(), std::back_inserter(v),
               [](const std::pair<const F, S> &x) { return x.first; });

или даже цикл for на основе диапазона, который, вероятно, самый элегантный и читаемый:

for(const auto &x : m) {
  v.push_back(x.first);
}
4 голосов
/ 06 октября 2011

До C ++ 11, вы можете использовать transform и структуру пользовательских функций:

template <class K, class V>
struct key_selector : std::unary_function<const std::pair<K, V>&, const K&>
{
    const K& operator()(const std::pair<K, V>& element) const
    {
        return element.first;
    }
};

transform(m.begin(), m.end(), back_inserter(v), key_selector<T,Z>());

Если у вас есть доступ к boost или TR1, вы можете заменить key_selector на mem_fn

transform(m.begin(), m.end(), back_inserter(v), mem_fn(&map<T,Z>::value_type::first));

Пост-C ++ 11, вы можете использовать лямбды:

transform(m.begin(), m.end(), back_inserter(v), [](const map<T,Z>::value_type& x) {return x.first;});
2 голосов
/ 06 октября 2011

В C ++ 11 вы можете использовать лямбда-выражения:

typedef std::map< std::string, std::string > map_t;
map_t map;
std::vector< std::string > v;

std::for_each(map.begin(), map.end(), [&v](map_t::value_type const& it)
        {
            v.push_back(it.first);
        });
1 голос
/ 06 октября 2011

Вы можете сделать что-то вроде:

std::transform(m.begin(), m.end(), std::back_inserter(v), FUNCTOR);

Где FUNCTOR зависит от того, какая у вас версия STL или библиотек и компиляторов.

C ++ 11 (лямбда)

std::transform(m.begin(), m.end(), std::back_inserter(v), [](map<T,Z>::const_reference a) { return a.first; });

C ++ 11 (std :: get)

std::transform(m.begin(), m.end(), std::back_inserter(v), &std::get<0>);

C ++ В SGI STL есть функтор select1st, который можно использовать

std::transform(m.begin(), m.end(), std::back_inserter(v), select1st);

C ++ 03 (не C ++ 11) с использованием объекта-функтора, как описывали другие люди.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...