How to create a custom comparator to insert and sort elements by value in a map in C++? Generally in a map, elements are sorted by key. I want to soet by value.
This is not possible in C++ to sort map based on its values due to its internal implementation.
Map sorts elements only based on its key.
But there is a way you can achieve what you want.(Both needs additional space though.)
1) If you only want all the values to be sorted & not needing their mapping. You can put all the keys in a vector and then sort the vector.
2) And suppose you want that mapping too. Then you can create a vector of pair<> and then define a comparator to sort based on second value of pair.
bool sortBySecond(const pair<int, int> &a, const pair<int, int> &b){
return (a.second < b.second);
}
Inside main:
vector<pair<int, int> > vect;
sort(vect.begin(), vect.end(), sortBySecond);
The above vector will have pair sorted on the basis of your values of map in ascending order.
Related
I want to find the max element of vector of pairs.
My criteria is: the max element is one with highest second value of the pair.
I did this:
auto max_angle = std::max_element(begin(angles), end(angles),
[](const std::pair<int, int>& left, const std::pair<int, int>& right){
return left.second < right.second;
});
Is it possible to do it without writing a predicate? Is there any easier way for pairs since it is a std struct?
No you can't, because by default std::pairs are compared lexicographically, meaning element-wise left to right. As such, your solution is the simplest solution you can have.
I am trying to write a sorting algorithm for the following unordered map. I have seen this question and I am trying to implement it for an unordered map, but it is not working!
Note- I am not allowed to use any STL sort functions.
void quickSort(unordered_map<string, int> map, unordered_map<string, int>::iterator left,unordered_map<string, int>::iterator right) {
unordered_map<string, int>::iterator i=left;
unordered_map<string, int>::iterator j=right;
unordered_map<string, int>::iterator pivot = std::advance(map.begin(), map.size() / 2);
unordered_map<string, int> tmp;
}
int main(){
unordered_map<string, int> map;
map["blah"] = 2;
map["the"] = 5;
quickSort(map,map.begin(),map.end());
}
As stated in the comments, you cannot sort a unordered_map in place because its value_type is std::pair<const Key, T> (note the const!) for an unordered_map<Key,T>. This means that you cannot swap elements in the map, so you cannot sort it. You will need to copy the data into another data-structure like a vector, then you can use some "home-grown" version of std::nth_element on it:
std::vector<std::pair<Key,T>> med {map.begin(), map.end()};
my_nth_element(med.begin(), med.end(), med.begin() + med.size() / 2);
auto median = med[med.size()/2];
You should implement your nth_element with linear complexity on average. (If the number of input values happens to be even, you need to use the mean of both middle-values.)
An unordered map does not have order(as its name implies) and thus finding the median in an unordered map does not make sense. If you need to find the median - use a auxiliary array and perform some implementation of nth_element algorithm in it. This step would be with linear complexity.
HOW to sort vectors inside a map based on the size of the vectors?
example:
map<int, vector<int> >
sort based on the size of the vector in order to remove some elements later within the less size.
1,2,3,4
2,5
6,7,8
after sort and delete ...
1,2,3,4
6,7,8
5
I hope this clarify the intended need.
Thanks
A map is an ordered container on which the order predicate applies to the key.
For example you can have a std::map<int, std::vector<int>, std::less<int> >
Here your key is not the vector, hence you cannot do what you are looking for with your map.
Here maybe you want a std::map<std::vector<int>, int, some_struct> where some_struct is a functor that defines a strict order relationship on your vectors.
You can do it provided the size of the vector doesn't change:
map <int, vector<int> > amap;
vector <int> v;
v.push_back( 42 );
amap.insert( make_pair( v.size(), v ));
If the size of the vector does change, you would have to remove the old entry and re-insert.
I have this multimap built to map the hamming distance of a string to its corresponding string.
Since the hamming distance of two strings could be the same, I want them to be sorted in ascending order. However when I print it out, it is not sorted. The hamdistArray is declared as an unsigned type.
typedef multimap<unsigned, string, less<unsigned> > Check;
Check pairs;
pairs.insert(Check::value_type(hamdistArray[j], d.sortedWordDatabase[j]));
for(Check::const_iterator iter = pairs.begin(); iter != pairs.end(); ++iter)
{
cout << iter->first << '\t' << iter->second<< endl;
}
Elements in a multimap are sorted by the key (in this case the unsigned hamming distance). Elements with the same key are not sorted by the value (in this case the string), they are usually kept in the order in which they were inserted.
This is not possible using std::multimap, because when keys are compared, it is not known which value they represent.
multimap only sorts by its key (length) not also by value (string). In this case I suspect your best approach is a std::map<unsigned, std::set<std::string> >. You could also use a std::set<std::pair<unsigned, std::string> > but searching would require you to construct dummy pairs to search on.
The less template function is not necessary since it's the default. Try declaring Check without as:
typedef multimap<unsigned, string> Check;
Edited: The best way to do this is to generate a hash-key as the *key_type* and than the value-type could be a std::pair<unsigned, string>
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() );