How to Use Sort() in C++ with Custom Sort Member Function

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



Leave a reply



Submit