I'd like to sort a map<pair<string, int>, int> dbg; by value using lambda :
For this I have
void test()
{
map<pair<string, int>, int> dbg;
sort( dbg.begin(), dbg.end(),
[]( pair<pair<string, int>, int>& lht, pair<pair<string, int>, int>& rht) {
return lht.second > rht.second;
});
}
But compilation failed with a lot of errors. What is the right lamda prototype here?
Sorting a map is nonsensical; it's already sorted, and you can't change the sort order after the fact by sorting it (the order can't be changed at all except by adding and removing elements, and they'll always fall into a fixed order). If you want to sort it in a different way, either:
Provide the alternate comparator to map so it's naturally sorted the way you want, or
Copy the entries to sequence type (e.g. vector) and sort that.
In this case, you want to sort by the value, which is not possible for a map, so option #2 is your only option.
Related
For example I've got a map like this:
std::map<std::map<pair<int, int>, pair<int, int> >, int> mp;
How do I insert/access element into/in that map?
For inserting I've tried with
// using nested map
std::map<pair<int, int>, pair<int, int> > mp2;
mp2.insert(make_pair(1,2), make_pair(3,4));
mp.insert(make_pair(mp2, 1));
For accessing the elements, I couldn't insert element into the map so I don't know if I did it right or wrong, but I think it is gonna be like this
mp[[1,2],[3,4]];
And the compiler throws a lot of errors . Some even navigate me to the implementation code of std::map, or to be more specific, the stl_tree.h thing.
What's wrong? I'm just a mere beginner so any help would be genuinely appreciated.
In addition, this is my homework. Basically I have to store coordinates like (x,y) and (i,j) to form a path into a container, and I've tried with vectors but I couldn't pass the time limit.
Please reconsider your choice of data structure. Using std::map as a key to std::map will incur large overheads due to necessity of creating temporary keys to compare (when accessing outer map elements). It's highly unlikely that it will help you get through the time limit of yours.
std::map::insert requires a ready std::pair<Key, Value>, which means you need to wrap your arguments in one more std::make_pair
mp2.insert(std::make_pair(std::make_pair(1,2), std::make_pair(3,4)));
Or you can replace insert with emplace
mp2.emplace(make_pair(1,2), make_pair(3,4));
To access elements you must construct a temporary map to be used as a key:
mp[{{{1,2},{3,4}}}]; //extra {} required
See it online
As pointed out by #Yksisarvinen, you should reconsider using a map as a key to another map.
That being said, I guess you forgot an enclosing std::make_pair() at:
mp2.insert(make_pair(make_pair(1,2), make_pair(3,4)));
For accessing that, you'd need to do something like:
template <class K, class V>
std::map<K, V> make_map(std::pair<K, V>&& pair)
{
return std::map<K, V> { pair };
}
mp[make_map(make_pair(make_pair(1 ,2), make_pair(3 , 4)))]
But beware that this is very inefficient!
Currently I am getting the set difference of two maps and then iterating through the resulting map.
Ideally I want to create a vector of the difference instead of a map. That way I iterate more efficiently.
typedef std::map<int, Info> RegistrationMap;
RegistrationMap redundantRegs;
std::set_difference(map1.begin(), map1.end(), map2.begin(), map2.end(),
std::inserter(redundantRegs, redundantRegs.begin()),
[](const std::pair<int, Info> &p1, const std::pair<int, Info> &p2 {return p1.first < p2.first;});
for (auto reg : redundantRegs)
{
map2[hiu.first].Status = "delete";
}
How would you create a vector of the set difference instead? Can this be done within the set_difference function?
I'm looking for the most efficient way possible of getting the difference.
std::set_difference can write its output to any output iterator, so there is no problem with writing the output into a vector:
std::vector<std::pair<int, Info>> redundantRegs;
std::set_difference(map1.begin(), map1.end(), map2.begin(), map2.end(),
std::back_inserter(redundantRegs),
...);
(Note: In your comparator, change std::pair<int, Info> to std::pair<const int, Info> to avoid unnecessary copies.)
You can use std::set_difference but instead of std::inserter you better use std::back_inserter as that is most efficient on std::vector, and create std::vector accordingly:
std::vector<RegistrationMap::value_type> redundantRegs;;
std::set_difference(map1.begin(), map1.end(), map2.begin(), map2.end(),
std::back_inserter(redundantRegs) );
Note: in the way you wrote it you do not need to write comparator explicitly, default one will work just fine. If you do not use default one, you better get it from the std::map using std::map::value_comp() instead of writing it explicitly as sorting criteria must match for map and std::set_difference:
std::set_difference(map1.begin(), map1.end(), map2.begin(), map2.end(),
std::back_inserter(redundantRegs),
map1.value_comp() );
Live example
I have defined a C++ priority queue like this:
priority_queue<pair<int,int>, vector<pair<int,int>>, decltype(&mygreater)> frontier(&mygreater);
with a custom mygreater function() like this:
bool mygreater(pair<int,int> v1, pair<int,int> v2) {
return v1.first > v2.first;
}
However, when I try to push a vector of pairs of ints onto the priority queue, I keep getting a ton of errors, including:
error: no matching function for call to ‘std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int> >, bool (*)(std::pair<int, int>, std::pair<int, int>)>::push(std::vector<std::pair<int, int> >&)’ frontier.push(temp);
Might anyone know what is causing the errors on my attempts to push to the priority queue? Any help is greatly appreciated.
This error has nothing to do with your custom comparison. You get the same error if you do this:
std::priority_queue<int> q;
std::vector<int> v;
q.push(v);
std::priority_queue::push takes a single object of whatever type you're storing, not a whole vector of them. The type you're storing is pair<int,int>, but you're trying to push vector<pair<int,int>>.
This is what I am trying right now. I made a comparison function:
bool compare(const std::pair<int, Object>& left, const std::pair<int, Object>& right)
{
return (left.second.name == right.second.name) && (left.second.time == right.second.time) &&
(left.second.value == right.second.value);
}
After I add an element I call std::unique to filter duplicates:
data.push_back(std::make_pair(index, obj));
data.erase(std::unique(data.begin(), data.end(), compare), data.end());
But it seems that this doesn't work. And I don't know what the problem is.
From my understanding std::unique should use the compare predicate.
How should I update my code to make this work ?
I am using C++03.
edit:
I have tried to sort it too, but still doens't work.
bool compare2(const std::pair<int, Object>& left, const std::pair<int, Object>& right)
{
return (left.second.time< right.second.time);
}
std::sort(simulatedLatchData.begin(), simulatedLatchData.end(), compare2);
std::unique requires the range passed to it to have all the duplicate elements next to one another in order to work.
You can use std::sort on the range before you a call unique to achieve that as sorting automatically groups duplicates.
Sorting and filtering is nice, but since you never want any duplicate, why not use std::set?
And while we're at it, these pairs look suspiciously like key-values, so how about std::map?
If you want to keep only unique objects, then use an appropriate container type, such as a std::set (or std::map). For example
bool operator<(object const&, object const&);
std::set<object> data;
object obj = new_object(/*...*/);
data.insert(obj); // will only insert if unique
I have this small program that reads a line of input & prints the words in it, with their respective number of occurrences. I want to sort the elements in the map that stores these values according to their occurrences. I mean, the words that only appear once, will be ordered to be at the beginning, then the words that appeared twice 7 so on. I know that the predicate should return a bool value, but I don't know what the parameters should be. Should it be two iterators to the map? If some one could explain this, it would be greatly appreciated. Thank you in advance.
#include<iostream>
#include<map>
using std::cout;
using std::cin;
using std::endl;
using std::string;
using std::map;
int main()
{
string s;
map<string,int> counters; //store each word & an associated counter
//read the input, keeping track of each word & how often we see it
while(cin>>s)
{
++counters[s];
}
//write the words & associated counts
for(map<string,int>::const_iterator iter = counters.begin();iter != counters.end();iter++)
{
cout<<iter->first<<"\t"<<iter->second<<endl;
}
return 0;
}
std::map is always sorted according to its key. You cannot sort the elements by their value.
You need to copy the contents to another data structure (for example std::vector<std::pair<string, int> >) which can be sorted.
Here is a predicate that can be used to sort such a vector. Note that sorting algorithms in C++ standard library need a "less than" predicate which basically says "is a smaller than b".
bool cmp(std::pair<string, int> const &a, std::pair<string, int> const &b) {
return a.second < b.second;
}
You can't resort a map, it's order is predefined (by default, from std::less on the key type). The easiest solution for your problem would be to create a std::multimap<int, string> and insert your values there, then just loop over the multimap, which will be ordered on the key type (int, the number of occurences), which will give you the order that you want, without having to define a predicate.
You are not going to be able to do this with one pass with an std::map. It can only be sorted on one thing at a time, and you cannot change the key in-place. What I would recommend is to use the code you have now to maintain the counters map, then use std::max_element with a comparison function that compares the second field of each std::pair<string, int> in the map.
A map has its keys sorted, not its values. That's what makes the map efficent. You cannot sort it by occurrences without using another data structure (maybe a reversed index!)
As stated, it simply won't work -- a map always remains sorted by its key value, which would be the strings.
As others have noted, you can copy the data to some other structure, and sort by the value. Another possibility would be to use a Boost bimap instead. I've posted a demo of the basic idea previously.
You probably want to transform map<string,int> to vector<pair<const string, int> > then sort the vector on the int member.
You could do
struct PairLessSecond
{
template< typename P >
bool operator()( const P& pairLeft, const P& pairRight ) const
{
return pairLeft.second < pairRight.second;
}
};
You can probably also construct all this somehow using a lambda with a bind.
Now
std::vector< std::map<std::string,int>::value_type > byCount;
std::sort( byCount.begin(), byCount.end(), PairLessSecond() );