开发者

Use STL to populate a vector<T> from map<T,Z>'s keys

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

Is there a nicer 1-line version using some STL function(s)?

edit: not using c++11!


Portable:

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

I think some implementations of STL have a non-standard extension called select1st, which is the equivalent of SelectKey shown here. As K-Ballo pointed out in the comments, there's also a TR1 version. I like the explicitly-named version as it's easier to see what's going on.

Since there's no need for state, you can get away with slightly less boilerplate by using an actual function rather than a functor:

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

If you could use C++11, you could use a lambda, which keeps the selection code close to where it's used:

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

or even range-based for-loop, which is probably the most elegant and readable:

for(const auto &x : m) {
  v.push_back(x.first);
}


Pre C++11, you could use transform and a custom function 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>());

If you have access to boost or TR1, you can replace key_selector with mem_fn

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

Post- C++11, you can use lambdas:

transform(m.begin(), m.end(), back_inserter(v), [](const map<T,Z>::value_type& x) {return x.first;});


In C++11, you can use lambda expressions:

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


You can do something along the lines of:

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

Where FUNCTOR depends on what version of the STL or libraries and compilers that you have.

C++11 (lambda)

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 has a functor called select1st which can be used

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

C++03 (Not C++11) using a functor object like other people have described.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜