Hello,
I've got a std::map<std::string, std::size_t>. How can I extract the
n-th biggest elements. For example:
the map: map["a"] = 5, map["b"] = 5, map["c"] = 7, map["d"] = 10, map["e"] = 10
I would like to get a map only with (n=3)
newmap["e"] = 10
newmap["d"] = 10
newmap["c"] = 7
I need only the key values, also a std::vector with ("e", "d", "c") can
be the result.
There's a standard-library algorithm for doing just such a job (the
std::nth_element() function template). Your requirement for selection
based on values (rather than keys) requires an extra level of indirection,
as pointed out by other replies, and my favourite of those suggestions is
to manipulate a set of copies of iterators into the map and then retrieve
the keys of those that meet your criterion.
So here's my solution:
#include <map>
#include <vector>
#include <algorithm>
template<typename map_iter_t>
struct compare_map_iters_by_value
{
bool operator()(map_iter_t const a, map_iter_t const b) const
{
return a->second < b->second;
}
};
template<typename map_t>
std::vector<typename map_t::key_type> const
n_biggest_elements(map_t const& map, std::size_t n)
{
typedef typename map_t::const_iterator map_iter_t;
typedef compare_map_iters_by_value<map_iter_t> compare_t;
typedef std::vector<map_iter_t> map_iters_t;
// make a list of iterators into the map
map_iters_t map_iters;
map_iters.reserve(map.size());
for (map_iter_t p = map.begin(); p != map.end(); ++p)
{
map_iters.push_back(p);
}
// arrange for just the last n items to be the largest-valued ones
// (this should be significantly quicker than std::sort() and friends)
std::nth_element(map_iters.begin(),
map_iters.end() - n,
map_iters.end(),
compare_t());
// extract the keys for those largest n items
std::vector<typename map_t::key_type> results;
results.reserve(n);
for (typename map_iters_t::const_iterator p = map_iters.end(); n > 0; --n)
{
results.push_back((*--p)->first);
}
return results;
}