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);
}
Есть ли более приятная 1-строчная версия, использующая некоторые функции STL?
изменить: не использовать С++ 11!
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);
}
Есть ли более приятная 1-строчная версия, использующая некоторые функции STL?
изменить: не использовать С++ 11!
Портативный:
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);
Если вы можете использовать С++ 11, вы можете использовать лямбду, которая держит код выбора близко к тому, где он используется:
std::transform(m.cbegin(), m.cend(), std::back_inserter(v),
[](const std::pair<const F, S> &x) { return x.first; });
или даже на основе диапазона для цикла, который, вероятно, наиболее изящный и читаемый:
for(const auto &x : m) {
v.push_back(x.first);
}
Pre С++ 11, вы можете использовать преобразование и настраиваемую функцию struct:
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));
Post-С++ 11, вы можете использовать lambdas:
transform(m.begin(), m.end(), back_inserter(v), [](const map<T,Z>::value_type& x) {return x.first;});
В С++ 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);
});
Вы можете сделать что-то по строкам:
std::transform(m.begin(), m.end(), std::back_inserter(v), FUNCTOR);
Где FUNCTOR зависит от версии STL или библиотек и компиляторов, которые у вас есть.
С++ 11 (lambda)
std::transform(m.begin(), m.end(), std::back_inserter(v), [](map<T,Z>::const_reference a) { return a.first; });
С++ 11 (std:: get)
std::transform(m.begin(), m.end(), std::back_inserter(v), &std::get<0>);
С++ SGI STL имеет функтор, называемый select1st, который можно использовать
std::transform(m.begin(), m.end(), std::back_inserter(v), select1st);
С++ 03 (Not С++ 11), используя объект-функтор, как описано другими людьми.