Multimap essentially has groups of data sorted by the key. I want a method by which I could access these individual groups and get their aggregate values.
For example, in a std::multimap< string, int > I store
{"Group1", 1},
{"Group1", 2},
{"Group1", 3},
{"Group2", 10},
{"Group2", 11},
{"Group2", 12}
Having stored these values, I should be able to iterate this multimap and get the aggregate values of each "group". Problem is there aren't any functions defined in STL to access MultiMaps in such a way. I could use lower_bound, upper_bound to manually iterate the multimap and total the group's contents, but I am hoping there could be better ways already defined in STL ? Can anyone propose a solution as to how I could get the aggregate values for a group in the above example.
pair<Iter, Iter> range = my_multimap.equal_range("Group1");
int total = accumulate(range.first, range.second, 0);
Is one way.
Edit:
If you don't know the group you are looking for, and are just going through each group, getting the next group's range can be done like so:
template <typename Pair>
struct Less : public std::binary_function<Pair, Pair, bool>
{
bool operator()(const Pair &x, const Pair &y) const
{
return x.first < y.first;
}
};
Iter first = mmap.begin();
Iter last = adjacent_find(first, mmap.end(), Less<MultimapType::value_type>());
// samekey.cpp -- Process groups with identical keys in a multimap
#include <iostream>
#include <string>
#include <map>
using namespace std;
typedef multimap<string, int> StringToIntMap;
typedef StringToIntMap::iterator mapIter;
int main ()
{
StringToIntMap mymap;
mymap.insert(make_pair("Group2", 11));
mymap.insert(make_pair("Group1", 3));
mymap.insert(make_pair("Group2", 10));
mymap.insert(make_pair("Group1", 1));
mymap.insert(make_pair("Group2", 12));
mymap.insert(make_pair("Group1", 2));
cout << "mymap contains:" << endl;
mapIter m_it, s_it;
for (m_it = mymap.begin(); m_it != mymap.end(); m_it = s_it)
{
string theKey = (*m_it).first;
cout << endl;
cout << " key = '" << theKey << "'" << endl;
pair<mapIter, mapIter> keyRange = mymap.equal_range(theKey);
// Iterate over all map elements with key == theKey
for (s_it = keyRange.first; s_it != keyRange.second; ++s_it)
{
cout << " value = " << (*s_it).second << endl;
}
}
return 0;
} // end main
// end samekey.cpp
If you already know the keys, you can use multimap::equal_range to get the iterators to the beginning and end of the group; use any standard algorithm to get the desired results from the range. If you don't know the keys, you can start at begin() and iterate through them yourself, comparing keys to find the start of each new group.
You can use an alternate container that can contain the aggregate sums of each group. To do this you might do something like:
template <class KeyType, class ValueType>
struct group_add {
typedef map<KeyType, ValueType> map_type;
map_type & aggregates;
explicit group_add(map_type & aggregates_)
: aggregates(aggregates_) { };
void operator() (map_type::value_type const & element) {
aggregates[element.first] += element.second;
};
};
template <class KeyType, class ValueType>
group_add<KeyType, ValueType>
make_group_adder(map<KeyType, ValueType> & map_) {
return group_add<KeyType, ValueType>(map_);
};
// ...
multimap<string, int> members;
// populate members
map<string, int> group_aggregates;
for_each(members.begin(), members.end(),
make_group_adder(group_aggregates));
// group_aggregates now has the sums per group
Of course, if you have Lambda's (in C++0x) it could be simpler:
multimap<string, int> members;
map<string, int> group_aggregates;
for_each(members.begin(), members.end(),
[&group_aggregates](multimap<string, int>::value_type const & element) {
group_aggregates[element.first] += element.second;
}
);
equal_range
Syntax:
#include <map>
pair<iterator, iterator> equal_range( const key_type& key );
The function equal_range() returns two iterators - one to the first element that contains key, another to a point just after the last element that contains key.
Not a multimap answer, but you can do things like the following if you so choose.
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <boost/assign/list_of.hpp>
#include <boost/foreach.hpp>
using namespace std;
using namespace boost;
using namespace boost::assign;
int main() {
typedef map<string, vector<int> > collection;
collection m;
m["Group 1"] = list_of(1)(2)(3);
m["Group 2"] = list_of(10)(11)(12);
collection::iterator g2 = m.find("Group 2");
if (g2 != m.end()) {
BOOST_FOREACH(int& i, g2->second) {
cout << i << "\n";
}
}
}
Related
Is there a prettier way to get a value from inside a vector in a map without using loops?
For example , How to get the key of the vector which has an element of value 50?
std::map < int , std::vector < int >> myMap;
std::vector < int > a= {10,20,30};
std::vector < int > b= {50,60,70};
myMap.insert({1000,a});
myMap.insert({2000,b});
Can I get the key(s) if the value is in more than one vector ?
For Example if 50 Is in both vectors ?
std::vector < int > a= {10,20,50};
std::vector < int > b= {50,60,70};
Here works for every map, value and inner container:
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <iterator>
#include <optional>
template <typename ValueT, typename MapT>
std::optional<typename MapT::key_type> find_key_for_value_contained_in_intern_container(const ValueT& value, const MapT& map) {
auto key_it = std::find_if(std::begin(map), std::end(map), [&value] (const auto & element) {
return std::find(std::begin(element.second), std::end(element.second), value) != std::end(element.second);
});
return (key_it != std::end(map)) ? key_it->first : std::optional<typename MapT::key_type>();
}
int main() {
std::map<int, std::vector<int >> myMap;
std::vector<int> a = {10, 20, 30};
std::vector<int> b = {50, 60, 70};
myMap.insert({1000, a});
myMap.insert({2000, b});
int value_to_search{50};
auto key = find_key_for_value_contained_in_intern_container(value_to_search, myMap);
if (key)
std::cout << "Value " << value_to_search << " is at key " << *key << "\n";
}
Is there a prettier way to get a value from inside a vector in a map without using loops?
You cannot avoid looping the map. But you can avoid writing the loop by using standard algorithm: std::find_if.
I mean more efficient
If you want the lookup to be efficient, then your choice of data structure is not good. You could instead use following:
std::unordered_multimap<int, int> myMap{
{10, 1000},
{20, 1000},
{30, 1000},
{50, 2000},
{60, 2000},
{70, 2000},
};
With this, the lookup has asymptotically constant complexity instead of linear.
If you need to be efficient to find the key from the value, and conversely, you could use two maps. If needed, you can encapsulate that into a single class. You are then paying for efficiency of search with space.
Something along the lines of:
class DoubleMap {
public:
DoubleMap() {}
void insert(int key, std::vector<int> value) {
myMap1.insert({key, value});
myMap2.insert({value, key});
}
std::vector<int> getValue (int key) {return myMap1[key];}
int getKey(std::vector<int> value) {return myMap2[value];}
private :
std::map <int, std::vector<int>> myMap1;
std::map<std::vector<int>, int> myMap2;
}
I wouldn't advise this kind of heavy class unless you really need the efficiency of search in both directions, though.
Say I have the following setup:
I have a boost::geometry::index::rtree that takes as a key a two-dimensional box and as a value a points.
The first dimension of the box, will in practice be applied to (real-valued closed) intervals, whereas the second only to point.
So my box looks like:
using namespace std;
typedef bg::model::point<unsigned long, 2, bg::cs::cartesian> _pt_t;
typedef bg::model::box<_pt_t> _box_t;
typedef pair<_box_t, unsigned long> tree_v_t;
typedef bgi::rtree<tree_v_t, bgi::quadratic<16> > rtree_t;
A box will allways be initialized using:
_box_t _mb(unsigned long i, unsigned long s, unsigned long d){
_box_t b(_pt_t(s, i), _pt_t(s + d, i));
return b;
}
Now let's say I have initialised the rtree and I want to do two sorts of complicate queries:
given a set si of intervalsset<pair<unsigned int, unsigned int> > and a set sp of points set<unsigned int>, I would like to iterate all the values that are the result of the following pseudocode query:
any(si, intersect(rtree_level1)) &&
any(sp, contains(rtree_level2)) &&
value in ps
In other words I want the subtree of the rtree that contains the intersection of intervals contained in si and of points contained in sp and that its values are also in sp. If you like you can assume that all intervals in si are disjoint.
given a set spi of points and intervals set<unsigned int, pair<unsigned int, unsigned int> >, I would like to iterate all the values that are the result of the following pseudocode query:
any(spi, intersect(rtree_level1)(spi.interval) &&
contains(rtree_level2)(spi.point) &&
value in spi.point
)
In other words I want the union of all subtrees that come from each element of spi, for which they are the intersection of the given interval and they contain only those points both as keys (second level) and values. This is like the union all the R-trees produced from query 1 if both si and sp have one element.
I can understand how I can do that using the satisfy predicate and applying transform to the iterator produced by qbegin, but
what is the most efficient way to do that in boost?
Here is a basic program with double index (R-tree and std::map) doing bi-directional indexing: from char to box/interval and from box/interval to char:
Includes, iostream is needed only for output.
#include <boost/geometry.hpp>
#include <map>
#include <vector>
#include <iostream>
Namespaces for convenience.
namespace bg = boost::geometry;
namespace bgi = boost::geometry::index;
Basic bi-directional index allowing to insert box/interval-char pairs and find box based on char or vector of chars based on box (intersecting). insert() merges boxes if needed.
template <typename Box, typename T>
class rtree_map_index
{
typedef std::map<T, Box> map_type;
typedef typename map_type::iterator map_iterator;
typedef typename map_type::const_iterator map_const_iterator;
typedef std::pair<Box, map_iterator> rtree_value;
typedef bgi::rtree<rtree_value, bgi::rstar<4> > rtree_type;
public:
void insert(Box const& box, T const& v)
{
std::pair<map_iterator, bool>
p = m_map.insert(std::make_pair(v, box));
map_iterator map_it = p.first;
T const& map_val = map_it->first;
Box & map_box = map_it->second;
// new key,value inserted into map
if (p.second)
{
// insert it to the r-tree
m_rtree.insert(rtree_value(map_box, map_it));
}
// key already exists in map and box has to be expanded
else if (! bg::covered_by(box, map_box))
{
// calculate expanded box
Box new_box = map_box;
bg::expand(new_box, box);
// update r-tree
m_rtree.remove(rtree_value(map_box, map_it));
m_rtree.insert(rtree_value(new_box, map_it));
// update map
map_box = new_box;
}
}
bool find(T const& v, Box & result) const
{
map_const_iterator it = m_map.find(v);
if (it != m_map.end())
{
result = it->second;
return true;
}
return false;
}
void find(Box const& box, std::vector<char> & result) const
{
std::vector<rtree_value> res;
m_rtree.query(bgi::intersects(box), std::back_inserter(res));
result.resize(res.size());
for (size_t i = 0; i < res.size(); ++i)
result[i] = res[i].second->first;
}
private:
rtree_type m_rtree;
map_type m_map;
};
Main function with basic use-case.
int main()
{
for 2-dimentional data stored in the r-tree (boxes).
{
typedef bg::model::point<double, 2, bg::cs::cartesian> point;
typedef bg::model::box<point> box;
rtree_map_index<box, char> index;
index.insert(box(point(0, 0), point(3, 3)), 'a');
index.insert(box(point(1, 1), point(4, 4)), 'a');
index.insert(box(point(5, 5), point(6, 6)), 'b');
box res1;
index.find('a', res1);
std::cout << bg::wkt(res1) << std::endl;
std::vector<char> res2;
index.find(box(point(4, 4), point(5, 5)), res2);
BOOST_ASSERT(res2.size() == 2);
std::cout << res2[0] << std::endl;
std::cout << res2[1] << std::endl;
}
for 1-dimensional data stored in the r-tree (intervals)
{
typedef bg::model::point<double, 1, bg::cs::cartesian> point;
typedef bg::model::box<point> box;
rtree_map_index<box, char> index;
index.insert(box(point(0), point(3)), 'a');
index.insert(box(point(1), point(4)), 'a');
index.insert(box(point(5), point(6)), 'b');
box res1;
index.find('a', res1);
std::cout << "(" << bg::get<0, 0>(res1) << ", " << bg::get<1, 0>(res1) << ")" << std::endl;
std::vector<char> res2;
index.find(box(point(4), point(5)), res2);
BOOST_ASSERT(res2.size() == 2);
std::cout << res2[0] << std::endl;
std::cout << res2[1] << std::endl;
}
The end.
return 0;
}
Note that instead of rtree you could use interval_map. You should be able to build on top of rtree_map_index. You could add a constructor creating map and rtree from a container of elements of type std::pair<Box, T> to take advantage from r-tree packing algorithm. You could implement whatever find() function you need. Etc.
I have a map defined as std::map<std::string, textInfo> tempMap;
the textInfo class has some attributes as textsize,textcolor,textfont etc..
I want to select an item from this map that matches with a given value to an attribute in textInfo class.
for example if the Map contains
<"A",textInfo("10","Red","Verdana")>
<"B",textInfo("12","Green","Timesnewroman")>
<"C",textInfo("11","Blue","Cambria")>
I want to select the item that contains "Cambria" in it textfont attribute.
<"C",textInfo("11","Blue","Cambria")>
std::find_if should work for your needs.
Sample program:
#include <iostream>
#include <map>
#include <algorithm>
struct textInfo
{
std::string textsize;
std::string textcolor;
std::string textfont;
};
int main()
{
std::map<std::string, textInfo> m =
{
{"A", {"10","Red","Verdana"}},
{"B", {"12","Green","Timesnewroman"}},
{"C", {"11","Blue","Cambria"}}
};
auto iter = std::find_if(m.begin(),
m.end(),
[](std::pair<std::string, textInfo> const& item)
{ return (item.second.textfont == "Cambria");});
if ( iter != m.end() )
{
auto& item = iter->second;
std::cout << item.textsize << ", " << item.textcolor << ", " << item.textfont << std::endl;
}
}
Output:
11, Blue, Cambria
You can only access maps directly via a key, here your std::string. To search for a value or even a variable inside a value like it's the case here you have to iterate over the whole map.
std::map<std::string, textInfo>::const_iterator it = tempMap.begin();
for (; it != tempMap.end(); ++it)
{
if (0 == tempMap[(*it)].textfont.equals("Cambria")) // You could use == operator if it's a std::string
{
break; // found
}
}
// Do something with the found item. If the iterator is tempMap.end(), nothing found!
Look here for more informations.
Multimap essentially has groups of data sorted by the key. I want a method by which I could access these individual groups and get their aggregate values.
For example, in a std::multimap< string, int > I store
{"Group1", 1},
{"Group1", 2},
{"Group1", 3},
{"Group2", 10},
{"Group2", 11},
{"Group2", 12}
Having stored these values, I should be able to iterate this multimap and get the aggregate values of each "group". Problem is there aren't any functions defined in STL to access MultiMaps in such a way. I could use lower_bound, upper_bound to manually iterate the multimap and total the group's contents, but I am hoping there could be better ways already defined in STL ? Can anyone propose a solution as to how I could get the aggregate values for a group in the above example.
pair<Iter, Iter> range = my_multimap.equal_range("Group1");
int total = accumulate(range.first, range.second, 0);
Is one way.
Edit:
If you don't know the group you are looking for, and are just going through each group, getting the next group's range can be done like so:
template <typename Pair>
struct Less : public std::binary_function<Pair, Pair, bool>
{
bool operator()(const Pair &x, const Pair &y) const
{
return x.first < y.first;
}
};
Iter first = mmap.begin();
Iter last = adjacent_find(first, mmap.end(), Less<MultimapType::value_type>());
// samekey.cpp -- Process groups with identical keys in a multimap
#include <iostream>
#include <string>
#include <map>
using namespace std;
typedef multimap<string, int> StringToIntMap;
typedef StringToIntMap::iterator mapIter;
int main ()
{
StringToIntMap mymap;
mymap.insert(make_pair("Group2", 11));
mymap.insert(make_pair("Group1", 3));
mymap.insert(make_pair("Group2", 10));
mymap.insert(make_pair("Group1", 1));
mymap.insert(make_pair("Group2", 12));
mymap.insert(make_pair("Group1", 2));
cout << "mymap contains:" << endl;
mapIter m_it, s_it;
for (m_it = mymap.begin(); m_it != mymap.end(); m_it = s_it)
{
string theKey = (*m_it).first;
cout << endl;
cout << " key = '" << theKey << "'" << endl;
pair<mapIter, mapIter> keyRange = mymap.equal_range(theKey);
// Iterate over all map elements with key == theKey
for (s_it = keyRange.first; s_it != keyRange.second; ++s_it)
{
cout << " value = " << (*s_it).second << endl;
}
}
return 0;
} // end main
// end samekey.cpp
If you already know the keys, you can use multimap::equal_range to get the iterators to the beginning and end of the group; use any standard algorithm to get the desired results from the range. If you don't know the keys, you can start at begin() and iterate through them yourself, comparing keys to find the start of each new group.
You can use an alternate container that can contain the aggregate sums of each group. To do this you might do something like:
template <class KeyType, class ValueType>
struct group_add {
typedef map<KeyType, ValueType> map_type;
map_type & aggregates;
explicit group_add(map_type & aggregates_)
: aggregates(aggregates_) { };
void operator() (map_type::value_type const & element) {
aggregates[element.first] += element.second;
};
};
template <class KeyType, class ValueType>
group_add<KeyType, ValueType>
make_group_adder(map<KeyType, ValueType> & map_) {
return group_add<KeyType, ValueType>(map_);
};
// ...
multimap<string, int> members;
// populate members
map<string, int> group_aggregates;
for_each(members.begin(), members.end(),
make_group_adder(group_aggregates));
// group_aggregates now has the sums per group
Of course, if you have Lambda's (in C++0x) it could be simpler:
multimap<string, int> members;
map<string, int> group_aggregates;
for_each(members.begin(), members.end(),
[&group_aggregates](multimap<string, int>::value_type const & element) {
group_aggregates[element.first] += element.second;
}
);
equal_range
Syntax:
#include <map>
pair<iterator, iterator> equal_range( const key_type& key );
The function equal_range() returns two iterators - one to the first element that contains key, another to a point just after the last element that contains key.
Not a multimap answer, but you can do things like the following if you so choose.
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <boost/assign/list_of.hpp>
#include <boost/foreach.hpp>
using namespace std;
using namespace boost;
using namespace boost::assign;
int main() {
typedef map<string, vector<int> > collection;
collection m;
m["Group 1"] = list_of(1)(2)(3);
m["Group 2"] = list_of(10)(11)(12);
collection::iterator g2 = m.find("Group 2");
if (g2 != m.end()) {
BOOST_FOREACH(int& i, g2->second) {
cout << i << "\n";
}
}
}
How can i get the top n keys of std::map based on their values?
Is there a way that i can get a list of say for example the top 10 keys with the biggest value as their values?
Suppose we have a map similar to this :
mymap["key1"]= 10;
mymap["key2"]= 3;
mymap["key3"]= 230;
mymap["key4"]= 15;
mymap["key5"]= 1;
mymap["key6"]= 66;
mymap["key7"]= 10;
And i only want to have a list of top 10 keys which has a bigger value compared to the other.
for example the top 4 for our mymap is
key3
key6
key4
key1
key10
note:
the values are not unique, actually they are the number of occurrences of each key. and i want to get a list of most occurred keys
note 2:
if map is not a good candidate and you want to suggest anything, please do it according to the c++11 ,i cant use boost at the time.
note3:
in case of using std::unordered_multimap<int,wstring> do i have any other choices?
The order of a map is based on its key and not its values and cannot be reordered so it is necessary to iterate over the map and maintain a list of the top ten encountered or as commented by Potatoswatter use partial_sort_copy() to extract the top N values for you:
std::vector<std::pair<std::string, int>> top_four(4);
std::partial_sort_copy(mymap.begin(),
mymap.end(),
top_four.begin(),
top_four.end(),
[](std::pair<const std::string, int> const& l,
std::pair<const std::string, int> const& r)
{
return l.second > r.second;
});
See online demo.
Choosing a different type of container may be more appropriate, boost::multi_index would be worth investigating, which:
... enables the construction of containers maintaining one or more indices with different sorting and access semantics.
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
int main(int argc, const char * argv[])
{
map<string, int> entries;
// insert some random entries
for(int i = 0; i < 100; ++i)
{
string name(5, 'A' + (char)(rand() % (int)('Z' - 'A') ));
int number = rand() % 100;
entries.insert(pair<string, int>(name, number));
}
// create container for top 10
vector<pair<string, int>> sorted(10);
// sort and copy with reversed compare function using second value of std::pair
partial_sort_copy(entries.begin(), entries.end(),
sorted.begin(), sorted.end(),
[](const pair<string, int> &a, const pair<string, int> &b)
{
return !(a.second < b.second);
});
cout << endl << "all elements" << endl;
for(pair<string, int> p : entries)
{
cout << p.first << " " << p.second << endl;
}
cout << endl << "top 10" << endl;
for(pair<string, int> p : sorted)
{
cout << p.first << " " << p.second << endl;
}
return 0;
}
Not only does std::map not sort by mapped-to value (such values need not have any defined sorting order), it doesn't allow rearrangement of its elements, so doing ++ map[ "key1" ]; on a hypothetical structure mapping the values back to the keys would invalidate the backward mapping.
Your best bet is to put the key-value pairs into another structure, and sort that by value at the time you need the backward mapping. If you need the backward mapping at all times, you would have to remove, modify, and re-add each time the value is changed.
The most efficient way to sort the existing map into a new structure is std::partial_sort_copy, as (just now) illustrated by Al Bundy.
since the mapped values are not indexed, you would have to read everything and select the 10 biggest values.
std::vector<mapped_type> v;
v.reserve(mymap.size());
for(const auto& Pair : mymap)
v.push_back( Pair.second );
std::sort(v.begin(), v.end(), std::greater<mapped_type>());
for(std::size_t i = 0, n = std::min<int>(10,v.size()); i < n; ++i)
std::cout << v[i] << ' ';
another way, is to use two maps or a bimap, thus mapped values would be ordered.
The algorithm you're looking for is nth_element, which partially sorts a range so that the nth element is where it would be in a fully sorted range. For example, if you wanted the top three items in descending order, you'd write (in pseudo C++)
nth_element(begin, begin + 3, end, predicate)
The problem is nth_element doesn't work with std::map. I would therefore suggest you change your data structure to a vector of pairs (and depending on the amount of data you're dealing with, you may find this to be a quicker data structure anyway). So, in the case of your example, I'd write it like this:
typedef vector<pair<string, int>> MyVector;
typedef MyVector::value_type ValueType;
MyVector v;
// You should use an initialization list here if your
// compiler supports it (mine doesn't...)
v.emplace_back(ValueType("key1", 10));
v.emplace_back(ValueType("key2", 3));
v.emplace_back(ValueType("key3", 230));
v.emplace_back(ValueType("key4", 15));
v.emplace_back(ValueType("key5", 1));
v.emplace_back(ValueType("key6", 66));
v.emplace_back(ValueType("key7", 10));
nth_element(v.begin(), v.begin() + 3, v.end(),
[](ValueType const& x, ValueType const& y) -> bool
{
// sort descending by value
return y.second < x.second;
});
// print out the top three elements
for (size_t i = 0; i < 3; ++i)
cout << v[i].first << ": " << v[i].second << endl;
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <algorithm>
#include <cassert>
#include <iterator>
using namespace std;
class MyMap
{
public:
MyMap(){};
void addValue(string key, int value)
{
_map[key] = value;
_vec.push_back(make_pair(key, value));
sort(_vec.begin(), _vec.end(), Cmp());
}
vector<pair<string, int> > getTop(int n)
{
int len = min((unsigned int)n, _vec.size());
vector<Pair> res;
copy(_vec.begin(), _vec.begin() + len, back_inserter(res));
return res;
}
private:
typedef map<string, int> StrIntMap;
typedef vector<pair<string, int> > PairVector;
typedef pair<string, int> Pair;
StrIntMap _map;
PairVector _vec;
struct Cmp:
public binary_function<const Pair&, const Pair&, bool>
{
bool operator()(const Pair& left, const Pair& right)
{
return right.second < left.second;
}
};
};
int main()
{
MyMap mymap;
mymap.addValue("key1", 10);
mymap.addValue("key2", 3);
mymap.addValue("key3", 230);
mymap.addValue("key4", 15);
mymap.addValue("key6", 66);
mymap.addValue("key7", 10);
auto res = mymap.getTop(3);
for_each(res.begin(), res.end(), [](const pair<string, int> value)
{cout<<value.first<<" "<<value.second<<endl;});
}
The simplest solution would be to use std::transform to build
a second map:
typedef std::map<int, std::string> SortedByValue;
SortedByValue map2;
std::transform(
mymap.begin(), mymap.end(),
std::inserter( map2, map2.end() ),
[]( std::pair<std::string, int> const& original ) {
return std::pair<int, std::string>( original.second, original.first );
} );
Then pick off the last n elements of map2.
Alternatively (and probably more efficient), you could use an
std::vector<std::pair<int, std::string>> and sort it
afterwards:
std::vector<std::pair<int, std::string>> map2( mymap.size() );
std::transform(
mymap.begin(), mymap.end()
map2.begin(),
[]( std::pair<std::string, int> const& original ) {
return std::pair<int, std::string>( original.second, original.first );
} );
std::sort( map2.begin(), map2.end() );
(Note that these solutions optimize for time, at the cost of
more memory.)