Sort a vector c++ [duplicate] - c++

This question already has answers here:
Sorting a vector of custom objects
(14 answers)
Closed 9 years ago.
I am trying to sort a 2D vector with the type:
vector<pair<char, double>> output;
I am trying to arrange them from the highest to lowest double value and only displaying the top 5. This is what I am trying to do:
sort(output.begin(), output.end());
But this sort is not working properly for me. What am I doing wrong?

By default, std::sort will use the less-than comparison operator for the elements of the container, which will perform am lexicographical comparison using the char first and then the double.
You can use your own ordering function/functor that orders based on the pair's double element only:
bool cmp(const std::pair<char, double>& lhs,
const std::pair<char, double>& rhs)
{
return lhs.second > rhs.second;
}
then
std::vector<std::pair<char, double>> output = ....;
sort(output.begin(), output.end(), cmp);
See working demo here.

As Violet said, you may want to include your own comparison function:
class compare
{
public:
bool operator() (std::pair<char, int> const& p1,
std::pair<char, int> const& p2) const
{
// perform logic here
}
} Predicate;
std::sort uses operator < to compare the elements, and sorts them accordingly. It has an extra optional parameter for the comparsion functor, which we can include like this:
std::sort(output.begin(), output.end(), Predicate);
Note that this can also be done using a lambda in C++11.

Is there a reason you're using a vector of pairs? In other words, does the order in which the elements are stored internally really matter to you? If not, you're probably better off using a map<double,char> with a reverse iterator to get the last 5 elements sorted by double value.

You need to write a comparison operator between the pair<char, double> operands.
http://en.cppreference.com/w/cpp/algorithm/sort

Related

Sorting a Vector of Vector in Cpp

Say I have this vector of vector [[5,10],[2,5],[4,7],[3,9]] and I want to sort it using the sort() method of cpp, such that it becomes this [[5,10],[3,9],[4,7],[2,5]] after sorting. That is I want to sort based on the second index.
Now I have written this code to sort this vector of vector, but it is not working correctly.
static bool compareInterval( vector<vector<int>> &v1, vector<vector<int>> &v2)
{
return (v1[0][1]>v2[0][1]);
}
sort(boxTypes.begin(), boxTypes.end(), compareInterval);
Can anyone tell me where I am going wrong and hwo can I correct it. Thanks in advance.
Your sort could look like
std::sort(boxTypes.begin(), boxTypes.end(), [](auto const& lhs, auto const& rhs) {
return lhs[1] > rhs[1];
});
in other words sorting by the [1] element of each vector and using > to sort in descending order. Note that in the lambda function lhs and rhs are of type const std::vector<int>&.
When your code is sorting vector of vectors then to the boolean function it passes two vectors (not vector of vectors), and compares them to determine if they need to be interchanged, or are they in correct positions relative to each other.
Hence, here you only need to compare 2 vectors (you have tried to compare vector of vectors).
The change you need to make in compareInterval is:
static bool compareInterval( vector<int> &v1, vector<int> &v2)
{
return (v1[1]>v2[1]);
}
Find my testing code below:
#include <bits/stdc++.h>
using namespace std;
static bool compareInterval( vector<int> &v1, vector<int> &v2)
{
return (v1[1]>v2[1]);
}
int main() {
vector<vector<int>> boxTypes = {{5,10},{2,5},{4,7},{3,9}};
sort(boxTypes.begin(), boxTypes.end(), compareInterval);
for(int i=0;i<4;i++)
cout<<boxTypes[i][0]<<" "<<boxTypes[i][1]<<"\n";
}
Range projections will come somewhat handy for this.
ranges::sort algorithm would receive:
just the vector to sort; no iterators to the begin and end.
(optionally) the function you want to use for sorting, greater in this case.
(optionally) the projection: for every element t of the original vector, which happens to be another vector of two elements, get its second element, i.e. t[1], and sort on that.
std::ranges::sort(boxTypes, std::ranges::greater{}, [](auto&& bt) { return bt[1]; });
Note I have only been able to have this compiling on msvc, not on gcc or clang (and with /std:c++latest, not even with /std:c++20; https://godbolt.org/z/9Kqfa9vhx).

How do I sort vector of struct container? [duplicate]

This question already has answers here:
Sorting a vector of custom objects
(14 answers)
Closed 5 years ago.
I have a struct:
struct particle {
double x;
double y;
double Th;
double wt;
};
I also have a vector vector<particle> vecHow do I sort the vector vec according to increasing data member wtI want my vector sorted with increasing double wtI thought of using std::sort but how do I compensate for the struct?
It is actually quite easy:
std::sort(vec.begin(), vec.end(),
[](const particle& a, const particle& b) -> bool
{
return a.wt < b.wt;
}
This sorts the vector, based on the value of wt, in increasing order.
You also have another option: Defining operator< for particle, as follows:
bool operator<(const particle& a, const particle& b)
{
return a.wt < b.wt;
}
Then, when calling std::sort, you can just do:
std::sort(vec.begin(), vec.end());
With the code above, std::sort will call operator< on each pair of particles, which now have overloads to compare them as such.
If you noticed, the lambda I used in the beginning is the same as the function overload I used above. This easily illustrates the beauty and flexibility of the STL and C++.

How to remove duplicates from a vector of pair<int, Object>

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

max_element on vector of pairs without "predicate"

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.

how to sort a vector in c++ according to the ratio of its values [duplicate]

This question already has answers here:
Standard library sort and user defined types
(3 answers)
Closed 8 years ago.
I have a vector that its elements consists of two integers. I want to compute the ratio of these 2 integers for every element first, and then sort the vector descending according to this ratio.
Have a look at std::sort. That function allows you to sort a collection using a predicate that you may specify yourself. In the example code below I create a vector of pairs. The cmp function compares two of these pairs by calculating the ratio for each and returning true if a's ratio is greater than b's.
So effectively you need to specify a function (or a function object, or lambda or whatever) that takes two arguments of your collections element-type and compares them. If a should come before b, then the function should return true, and if not then it should return false. That function is the third argument for std::sort
#include <algorithm>
#include <vector>
bool cmp(const std::pair<int, int>& a, const std::pair<int, int>& b)
{
// you should probably also add some code to prevent dividing by zero...
return (static_cast<double>(a.first)/a.second) > (static_cast<double>(b.first)/b.second);
}
int main()
{
std::vector<std::pair<int, int> > pairs;
std::sort(pairs.begin(), pairs.end(), &cmp);
}
In C++11:
#include <algorithm>
#include <vector>
int main ( )
{
typedef std::pair<int, int> elem_t;
std::vector<std::pair<int, int>> pairs;
std::sort(pairs.begin(), pairs.end(), [](elem_t const & e1, elem_t const & e2)
{
e1.first * e2.second < e1.second * e2.first;
});
}
If you don't know the [](...){...} syntax, it is a lambda-expression from c++11.
Note that comparing multiplies the way I done it has a better precision that dividing (because integer division takes place), but can lead to overflow.