How to use sort() in C++ with custom sort member function?
It is, but in general I would encourage just using a proper functor or a lambda:
Using a lambda:
std::sort(payloadIndices.begin(), payloadIndices.end(), [this](int a, int b){
return this->sortByWeights(a, b);
});
Alternatively using std::mem_fn
:
auto sorter = std::bind(std::mem_fn(SimpleGreedyMappingTechnique::sortByWeights), this);
std::sort(payloadIndices.begin(), payloadIndices.end(), sorter);
Alternatively using a functor:
namespace{
struct indicies_less_than
{
const SimpleGreedyMappingTechnique & mapping_tech;
indicies_less_than(const SimpleGreedyMappingTechnique & mapping_tech)
:mapping_tech(mapping_tech){}
bool operator()(int a, int b)
{
return mapping_tech.sortByWeights(a, b);
}
};
}
std::sort(payloadIndices.begin(), payloadIndices.end(), indicies_less_than(*this));
Note:
if the types being sorted were anything more complicated than an int
you would definitely want to pass them by const&
to prevent copying
std::sort using member function in the same class?
Example of a functor being used for std::sort. vector D is the data, vector I is the indices to D. I is sorted according to D with std::sort using the functor. std::sort only creates one instance of class lessthan, then uses that one instance for all of the compares.
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <vector>
typedef unsigned int uint32_t;
#define SIZE 16
class example{
public:
std::vector<uint32_t> D; // data
std::vector<uint32_t> I; // indices
example(void)
{
D.resize(SIZE);
I.resize(SIZE);
for(uint32_t i = 0; i < SIZE; i++){
D[i] = rand()%100;
I[i] = i;
}
}
void displaydata(void)
{
for(size_t i = 0; i < SIZE; i++)
std::cout << std::setw(3) << D[I[i]];
std::cout << std::endl;
}
class lessthan // lessthan functor for std::sort
{
public:
const example &x;
lessthan(const example &e ) : x(e) { }
bool operator()(const uint32_t & i0, const uint32_t & i1)
{
return x.D[i0] < x.D[i1];
}
};
void sortindices(void)
{
std::sort(I.begin(), I.end(), lessthan(*this));
}
};
int main()
{
example x;
x.displaydata();
x.sortindices();
x.displaydata();
return 0;
}
c++ sort custom function
You said "For example I need it to sort arrays each containing 3 integers by their 3rd int," and that you won't know which index (which column) is significant until run time.
If you are able to use C++11, it can be this simple:
void mysort(vector<vector<int>>& v, int col)
{
sort(v.begin(), v.end(),
[col](const vector<int>& a, const vector<int>& b) -> bool
{ return a[col] < b[col]; });
}
If you are restricted to C++98, you can do the same thing, but instead of a lambda, you must write a functor that takes the column as a constructor parameter:
class ColumnSort {
int col_;
public:
ColumnSort(int col): col_(col) { }
bool operator()(const vector& a, const vector& b) const {
return a[col_] < b[col_];
}
};
void mysort(vector< vector<int> >& v, int col)
{
sort(v.begin(), v.end(), ColumnSort(col));
}
Finally, if you want a multi-column sort, the functor would look like this, where cols
is an ordered list of columns to sort on:
class ColumnSort {
vector<int> cols_;
public:
ColumnSort(const vector<int>& cols): cols_(cols) { }
bool operator()(const vector<int>& a, const vector<int>& b) const {
for (int i = 0; i < cols_.size(); ++i) {
if (a[cols_[i]] == b[cols_[i]]) continue;
return a[cols_[i]] < b[cols_[i]];
}
return false;
}
};
std::sort - given a custom sort function, are multiple sort queries in one comparison possible?
If you just want lexicographic ordering, std::tuple
will help you out:
bool customSort(const Custom &a, const Custom &b)
{
return std::tie(a.value1, a.value2) < std::tie(b.value1, b.value2);
}
Sort depending on member function of the object
Following on from the comments on the OP; you can refactor the lambda into its own functor for use the std::sort
, or you could use a C++03 style by combining the std::greater
, std::mem_fun
with a bind (possibly std::bind
) of some sort etc.; the C++03 style will be cumbersome to work with though.
The functor solution requires the call operator (operator()
) to have the appropriate signature; accept the required values and return a bool
, the const
method and const&
parameters are not needed, but by convention usually appear.
struct compare_rect_greater {
bool operator()(cv::Rect const& l, cv::Rect const& r) const
{
return l.area() > r.area();
}
};
// ...
std::vector<cv::Rect> regions;
std::sort(begin(regions), end(regions), compare_rect_greater());
The float
return from the area()
function will work as expected with the operator >
.
But considering the language level, ease of readability etc. your lambda is possible still the better solution.
std::vector<cv::Rect> regions;
std::sort(begin(regions), end(regions), [](cv::Rect const& l, cv::Rect const& r){
return l.area() > r.area();
});
The C++03 style is unwieldily to create and use in this case, I would not venture too far down this road.
Sorting a vector of custom objects
A simple example using std::sort
struct MyStruct
{
int key;
std::string stringValue;
MyStruct(int k, const std::string& s) : key(k), stringValue(s) {}
};
struct less_than_key
{
inline bool operator() (const MyStruct& struct1, const MyStruct& struct2)
{
return (struct1.key < struct2.key);
}
};
std::vector < MyStruct > vec;
vec.push_back(MyStruct(4, "test"));
vec.push_back(MyStruct(3, "a"));
vec.push_back(MyStruct(2, "is"));
vec.push_back(MyStruct(1, "this"));
std::sort(vec.begin(), vec.end(), less_than_key());
Edit: As Kirill V. Lyadvinsky pointed out, instead of supplying a sort predicate, you can implement the operator<
for MyStruct
:
struct MyStruct
{
int key;
std::string stringValue;
MyStruct(int k, const std::string& s) : key(k), stringValue(s) {}
bool operator < (const MyStruct& str) const
{
return (key < str.key);
}
};
Using this method means you can simply sort the vector as follows:
std::sort(vec.begin(), vec.end());
Edit2: As Kappa suggests you can also sort the vector in the descending order by overloading a >
operator and changing call of sort a bit:
struct MyStruct
{
int key;
std::string stringValue;
MyStruct(int k, const std::string& s) : key(k), stringValue(s) {}
bool operator > (const MyStruct& str) const
{
return (key > str.key);
}
};
And you should call sort as:
std::sort(vec.begin(), vec.end(),greater<MyStruct>());
Related Topics
C++ Overloading Array Operator
What Are Your Favorite C++ Coding Style Idioms
How to Solve Memory Fragmentation
Detect Windows or Linux in C, C++
Easy Framework for Opengl Shaders in C/C++
Does New[] Call Default Constructor in C++
Invalid Use of Incomplete Type
Linking with Clang++ on Os X Generates Lots of Symbol Not Found Errors
Can Compiler Generate Std::Move for a Last Use of Lvalue Automatically
Best Introduction to C++ Template Metaprogramming
Why Would I Prefer Using Vector to Deque
How to Create a Dll with Swig from Visual Studio 2010
How to Use Valgrind with Python C++ Extensions