Я хотів би відсортувати vector
vector<myClass> object;
Де myclass
містить багато int
змінних. Як я можу відсортувати своє vector
за будь-якою конкретною змінною даних myClass
.
Я хотів би відсортувати vector
vector<myClass> object;
Де myclass
містить багато int
змінних. Як я можу відсортувати своє vector
за будь-якою конкретною змінною даних myClass
.
Відповіді:
Перевантажте менше, ніж оператор, потім сортуйте. Це приклад, який я знайшов в Інтернеті ...
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());
Джерело: тут
std::sort(object.begin(), object.end(), pred());
де, pred()
- об'єкт функції, що визначає порядок на об'єктах myclass
. Крім того, ви можете визначити myclass::operator<
.
Наприклад, ви можете пройти лямбду:
std::sort(object.begin(), object.end(),
[] (myclass const& a, myclass const& b) { return a.v < b.v; });
Або якщо ви застрягли в C ++ 03, підхід до функціонального об'єкта ( v
є елементом, за яким ви хочете сортувати):
struct pred {
bool operator()(myclass const & a, myclass const & b) const {
return a.v < b.v;
}
};
Вказівник на учасника дозволяє написати єдиний компаратор, який може працювати з будь-яким членом даних вашого класу:
#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";
}
Вихід:
sorted by string field, c: x y
sorted by integer field, a: y x
sorted by integer field, b: x y
template <typename T, typename U, U (T::*F)> struct CompareByMember2 { bool operator()(const T &lhs, const T & rhs) { return lhs.*F < rhs.*F; }};
. Чи можливо це залежить, чи використовує виклик змінну, за якою член сортує, або різні абоненти вказують різних конкретних членів.
Як пояснено в інших відповідях, вам потрібно надати функцію порівняння. Якщо ви хочете зберегти визначення цієї функції близько до sort
виклику (наприклад, якщо це має сенс лише для такого сортування), ви можете визначити його тут boost::lambda
. Використовуйте boost::lambda::bind
для виклику функції-члена.
Наприклад, щоб сортувати за змінною-членом або функцією 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));
це мій підхід до вирішення цього загалом. Він розширює відповідь Стіва Джессопа, вилучаючи вимогу явно встановлювати аргументи шаблону та додаючи опцію також використовувати функтоїни та покажчики на методи (геттери)
#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;
}