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.
Related
I'd like to sort m_correlationValues in descending order and get ids of the sorted list. I've got this error. I'll appreciate your help.
no match for 'operator=' (operand types are 'std::vector<std::pair<int, float> >' and 'void')
return idx_correlation.second; });
void MatrixCanvas::SortMatrix()
{
int naxes = (int) m_correlationData.size();
std::vector<std::pair<int,float>> idx_correlations;
std::vector<std::pair<int,float>> sorted;
std::vector<int> idxs(naxes);
for(int idx =0; idx<naxes;idx++){
idx_correlations[idx] = std::make_pair(idx, m_correlationValues[chosen_row_id][idx]);}
// Wrong
sorted = std::sort(idx_correlations.begin(),
idx_correlations.end(),
[](std::pair<int,float> &idx_correlation){
return idx_correlation.second; });
// this will contain the order:
for(int i =0; i<naxes;i++)
idxs[i] = sorted[i].first;
}
You have two problems:
sort does not return a copy of the sorted range. It modifies the range provided. If you want the original to be left alone, make a copy of it first and then sort it.
std::sort's third argument is a comparator between two values, which has the meaning of "less than". That is, "does a come before b?" For keeping the line short, I replaced your pair<...> type with auto in the lambda, but it'll be deduced to "whatever type of thing" is being sorted.
Note, if you want decreasing, just change < to > in the lambda when it compares the two elements.
Possible fix:
auto sorted = idx_correlations; // full copy
std::sort(sorted.begin(),
sorted.end(),
[](auto const & left, auto const & right) {
return left.first < right.first; });
After that, sorted will be a sorted vector and idx_correlations will be left unchanged. Of course, if you don't mind modifying your original collection, there's no need to make this copy (and you can take begin/end of idx_correlations.
So the main issue I can see in your code, is that you're expecting the std::sort to return the sorted vector, and this is NOT how it works.
https://en.cppreference.com/w/cpp/algorithm/sort
The solution in your case is to get the sorted vector out of the original vector, ie. sorted = idx_correlations then sort the new vector.
sorted = idx_correlations;
std::sort( sorted.begin(), sorted.end(), your_comparator... );
This will do the trick while also maintaining the original vector.
Update: another issue is that your comparator will have TWO arguments not one (two elements to compare for the sort).
The other answers covered proper use of std::sort, I wish to show C++20 std::rannges::sort which have projection functionality what is close to thing you've tried to do:
std::vector<std::pair<int, float>> idx_correlations;
.....
auto sorted = idx_correlations;
std::ranges::sort(sorted, std::greater{}, &std::pair<int, float>::second);
https://godbolt.org/z/4rzzqW9Gx
I was wondering if there's a way to sort my list of pairs based on the second element. Here is a code:
std::list<std::pair<std::string, unsigned int>> words;
words.push_back(std::make_pair("aba", 23);
words.push_back(std::make_pair("ab", 20);
words.push_back(std::make_pair("aBa", 15);
words.push_back(std::make_pair("acC", 8);
words.push_back(std::make_pair("aaa", 23);
I would like to sort my list words based in the integer element in decreasing order so that my list would be like:
<"aba", 23>,<"aaa", 23>,<"ab", 20>,<"aBa", 15>,<"acC", 8>
Also, is it possible to sort them by both the first and second element such that it sorts by the second elements first (by integer value), and then if there's two or more pairs with the same second element (i.e. same integer value), then it will sort those based on the first element in alphabetical order, then the first 2 pairs on my sorted list above would swap, so:
<"aaa", 23>,<"aba", 23>,<"ab", 20>,<"aBa", 15>,<"acC", 8>
I would like to sort my list words based in the integer element in decreasing order
The sorting predicate must return true if the first element (i.e., the first pair) passed precedes the second one in your established order:
words.sort([](auto const& a, auto const& b) {
return a.second > b.second;
});
Since you want to sort the list in decreasing order, the pair a will precede b if its second element (i.e., the int) is greater than b's second element.
Note that std::sort() doesn't work for sorting an std::list because it requires random access iterators but std::list only provides bidirectional iterators.
is it possible to sort them by both the first and second element such that it sorts by the second elements first (by integer value), and then if there's two or more pairs with the same second element (i.e. same integer value), then it will sort those based on the first element in alphabetical order
Assuming again decreasing order for the int element, just resort to the second element of the pairs when both int elements are the same:
lst.sort([](auto const& a, auto const& b) {
if (a.second > b.second)
return true;
if (a.second < b.second)
return false;
return a.first < b.first;
});
or more concise thanks to std::tie():
lst.sort([](auto const& a, auto const& b) {
return std::tie(b.second, a.first) < std::tie(a.second, a.first);
});
std::list has a member function std::list::sort that is supposed to do the sorting.
One of its two overloads accepts custom comparison function:
template <class Compare>
void sort(Compare comp);
which you can use as follows:
words.sort([](const std::pair<string, unsigned int> &x,
const std::pair<string, unsigned int> &y)
{
return x.second > y.second;
});
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
Given a vector of vectors, I want to find the vector with the laregest size, and I use the following code:
bool Longest(vector<int> &A, vector<int> &B){
return A.size()>B.size();
}
vector<vector<int> >::iterator max_itr= max_element(L.begin(),L.end(),Longest);
where L is a vector of vectors (vector<vector<int> >)
I keep getting the iterator point to the L.begin(). Any suggestions?
The comparison functor object passed to std::max_element should return true if the first operand is less than the second one. Your comparison has this the wrong way around. You need
bool Longest(const vector<int> &A, const vector<int> &B)
{
return A.size() < B.size();
}
Also note that it is better for the parameters to be const references because the comparison operation should not modify its operands.
Here's a working example.
I would like to partial sort this vector with a predicate as such
std::vector<std::pair<std::string, int>> vp;
std::partial_sort(vp.begin(), vp.begin()+10, [](const std::pair<std::string,int> &left, const std::pair<std::string,int> &right)
{
return left.second > right.second;
});
However I get the error
no matching function for call to ‘partial_sort(std::vector<std::pair<std::basic_string<char>, int> >::iterator, __gnu_cxx::__normal_iterator<std::pair<std::basic_string<char>, int>*, ....
The above works fine for std::sort and not for partial_sort any suggestions ?
Looking at some reference documentation, you will find that std::partial_sort requires 3 iterators, not 2: start, middle and end. It will re-arrange the range so that the range [start, middle) is sorted, and contains the smallest elements from the range [start, end).
Depending on what exactly you're trying to achieve, you need to provide an appropriate 3rd iterator. If you're trying to find the 10 smallest elements, just do this:
std::partial_sort(vp.begin(), vp.begin()+10, vp.end(), /*lambda as before*/);