How to sort an STL vector?

C++SortingStl

C++ Problem Overview


I would like to sort a vector

vector<myClass> object;

Where myclass contains many int variables. How can I sort my vector on any specific data variable of myClass.

C++ Solutions


Solution 1 - C++

std::sort(object.begin(), object.end(), pred());

where, pred() is a function object defining the order on objects of myclass. Alternatively, you can define myclass::operator<.

For example, you can pass a lambda:

std::sort(object.begin(), object.end(),
          [] (myclass const& a, myclass const& b) { return a.v < b.v; });

Or if you're stuck with C++03, the function object approach (v is the member on which you want to sort):

struct pred {
    bool operator()(myclass const & a, myclass const & b) const {
        return a.v < b.v;
    }
};

Solution 2 - C++

Overload less than operator, then sort. This is an example I found off the web...

class MyData
{
public:
  int m_iData;
  string m_strSomeOtherData;
  bool operator<(const MyData &rhs) const { return m_iData < rhs.m_iData; }
};

std::sort(myvector.begin(), myvector.end());

Source: here

Solution 3 - C++

A pointer-to-member allows you to write a single comparator, which can work with any data member of your class:

#include <algorithm>
#include <vector>
#include <string>
#include <iostream>

template <typename T, typename U>
struct CompareByMember {
    // This is a pointer-to-member, it represents a member of class T
    // The data member has type U
    U T::*field;
    CompareByMember(U T::*f) : field(f) {}
    bool operator()(const T &lhs, const T &rhs) {
        return lhs.*field < rhs.*field;
    }
};

struct Test {
    int a;
    int b;
    std::string c;
    Test(int a, int b, std::string c) : a(a), b(b), c(c) {}
};

// for convenience, this just lets us print out a Test object
std::ostream &operator<<(std::ostream &o, const Test &t) {
    return o << t.c;
}

int main() {
    std::vector<Test> vec;
    vec.push_back(Test(1, 10, "y"));
    vec.push_back(Test(2, 9, "x"));

    // sort on the string field
    std::sort(vec.begin(), vec.end(), 
        CompareByMember<Test,std::string>(&Test::c));
    std::cout << "sorted by string field, c: ";
    std::cout << vec[0] << " " << vec[1] << "\n";

    // sort on the first integer field
    std::sort(vec.begin(), vec.end(), 
        CompareByMember<Test,int>(&Test::a));
    std::cout << "sorted by integer field, a: ";
    std::cout << vec[0] << " " << vec[1] << "\n";

    // sort on the second integer field
    std::sort(vec.begin(), vec.end(), 
        CompareByMember<Test,int>(&Test::b));
    std::cout << "sorted by integer field, b: ";
    std::cout << vec[0] << " " << vec[1] << "\n";
}

Output:

sorted by string field, c: x y
sorted by integer field, a: y x
sorted by integer field, b: x y

Solution 4 - C++

Like explained in other answers you need to provide a comparison function. If you would like to keep the definition of that function close to the sort call (e.g. if it only makes sense for this sort) you can define it right there with boost::lambda. Use boost::lambda::bind to call the member function.

To e.g. sort by member variable or function data1:

#include <algorithm>
#include <vector>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/lambda.hpp>
using boost::lambda::bind;
using boost::lambda::_1;
using boost::lambda::_2;

std::vector<myclass> object(10000);
std::sort(object.begin(), object.end(),
    bind(&myclass::data1, _1) < bind(&myclass::data1, _2));

Solution 5 - C++

this is my approach to solve this generally. It extends the answer from Steve Jessop by removing the requirement to set template arguments explicitly and adding the option to also use functoins and pointers to methods (getters)

#include <vector>
#include <iostream>
#include <algorithm>
#include <string>
#include <functional>

using namespace std;

template <typename T, typename U>
struct CompareByGetter {
	U (T::*getter)() const;
	CompareByGetter(U (T::*getter)() const) : getter(getter) {};
	bool operator()(const T &lhs, const T &rhs) {
		(lhs.*getter)() < (rhs.*getter)();
	}
};

template <typename T, typename U>
CompareByGetter<T,U> by(U (T::*getter)() const) {
	return CompareByGetter<T,U>(getter);
}

//// sort_by
template <typename T, typename U>
struct CompareByMember {
    U T::*field;
    CompareByMember(U T::*f) : field(f) {}
    bool operator()(const T &lhs, const T &rhs) {
        return lhs.*field < rhs.*field;
    }
};

template <typename T, typename U>
CompareByMember<T,U> by(U T::*f) {
	return CompareByMember<T,U>(f);
}

template <typename T, typename U>
struct CompareByFunction {
	function<U(T)> f;
	CompareByFunction(function<U(T)> f) : f(f) {}
	bool operator()(const T& a, const T& b) const {
		return f(a) < f(b);
	}
};

template <typename T, typename U>
CompareByFunction<T,U> by(function<U(T)> f) {
	CompareByFunction<T,U> cmp{f};
	return cmp;
}

struct mystruct {
	double x,y,z;
	string name;
	double length() const {
		return sqrt( x*x + y*y + z*z );
	}
};

ostream& operator<< (ostream& os, const mystruct& ms) {
	return os << "{ " << ms.x << ", " << ms.y << ", " << ms.z << ", " << ms.name << " len: " << ms.length() << "}";
}

template <class T>
ostream& operator<< (ostream& os, std::vector<T> v) {
	os << "[";
	for (auto it = begin(v); it != end(v); ++it) {
		if ( it != begin(v) ) {
			os << " ";
		}
		os << *it;
	}
	os << "]";
	return os;
}

void sorting() {
	vector<mystruct> vec1 = { {1,1,0,"a"}, {0,1,2,"b"}, {-1,-5,0,"c"}, {0,0,0,"d"} };
	
	function<string(const mystruct&)> f = [](const mystruct& v){return v.name;};

	cout << "unsorted  " << vec1 << endl;
	sort(begin(vec1), end(vec1), by(&mystruct::x) );
	cout << "sort_by x " << vec1 << endl;
	sort(begin(vec1), end(vec1), by(&mystruct::length));
	cout << "sort_by len " << vec1 << endl;
	sort(begin(vec1), end(vec1), by(f) );
	cout << "sort_by name " << vec1 << endl;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNativeCoderView Question on Stackoverflow
Solution 1 - C++avakarView Answer on Stackoverflow
Solution 2 - C++GabeView Answer on Stackoverflow
Solution 3 - C++Steve JessopView Answer on Stackoverflow
Solution 4 - C++Benjamin BannierView Answer on Stackoverflow
Solution 5 - C++ArneView Answer on Stackoverflow