Vorrei ordinare una vector
Come ordinare un vettore STL?
vector<myClass> object;
Dove myclass
contiene molti int
variabili. Come posso ordinare il mio vector
su qualsiasi variabile dati specifica di myClass
.
Vorrei ordinare una vector
Come ordinare un vettore STL?
vector<myClass> object;
Dove myclass
contiene molti int
variabili. Come posso ordinare il mio vector
su qualsiasi variabile dati specifica di myClass
.
Sovraccarico inferiore all'operatore, quindi ordinare. Questo è un esempio che ho trovato fuori dal 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());
Fonte: here
std::sort(object.begin(), object.end(), pred());
dove, pred()
è un oggetto funzione che definisce l'ordine su oggetti di myclass
. In alternativa, è possibile definire myclass::operator<
.
Ad esempio, è possibile passare un lambda:
std::sort(object.begin(), object.end(),
[] (myclass const& a, myclass const& b) { return a.v < b.v; });
Oppure, se sei bloccato con C++ 03, l'approccio funzione di oggetto (v
è il membro su cui si desidera ordinare):
struct pred {
bool operator()(myclass const & a, myclass const & b) const {
return a.v < b.v;
}
};
@NativeCoder questo è ciò che l'operatore è per - si può definirlo comunque ti piace e in base a qualsiasi variabile tu voglia. si chiama Overloading degli operatori http://www.cs.caltech.edu/courses/cs11/material/cpp/donnie/cpp-ops.html. –
L'approccio predicato è molto meglio dell'approccio di overloading dell'operatore se non si dispone di un ordinamento generico di questa particolare classe ma si desidera solo ordinarlo per questo vettore. –
Un puntatore-a-membro consente di scrivere un singolo confronto, che può funzionare con qualsiasi membro di dati della classe :
#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";
}
uscita:
sorted by string field, c: x y
sorted by integer field, a: y x
sorted by integer field, b: x y
Ciao Steve, ho pensato di risolvere lo stesso problema di questa domanda senza molti progressi! La tua soluzione mi sembra molto buona. Penso che mi ci sarebbe voluto molto tempo per inventarlo, se mai! Ho letto Myers 'Effective C++ ed efficace STL e Dewhurst C++ Common Knowledge. Mi chiedo se potresti raccomandare qualche lettura in più, conosci qualche libro che copra esempi come quello sopra in particolare o, in mancanza, qualche suggerimento più generale per aiutarmi a vedere soluzioni del genere? –
@ Czarak: guardandolo di nuovo, probabilmente potrebbe essere migliorato. Ad esempio, potrebbe ottimizzare meglio se il puntatore al membro fosse un parametro del template: 'template
@ Czarak: come per la lettura, non ne sono sicuro. Il "trucco" qui è la combinazione di puntatori membri con i modelli, penso che sia una questione di essere a proprio agio nello scrivere modelli e sapere cosa si può fare con loro. Vandevoorde & Josuttis 'book "C++ Templates - The Complete Guide" dovrebbe essere buono, ma non l'ho letto. Potrebbe essere abbastanza vecchio e abbastanza costoso che ora c'è un'opzione migliore. Guarda http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list. E nota che se hai C++ 0x, una funzione lambda potrebbe battere la scrittura dell'intera classe per questo! –
Come spiegato in altre risposte è necessario pro vide una funzione di confronto. Se si desidera mantenere la definizione di tale funzione vicino alla chiamata sort
(ad esempio se ha senso solo per questo tipo) è possibile definirla proprio lìcon boost::lambda
. Utilizzare boost::lambda::bind
per chiamare la funzione membro.
Ad es. ordina per membro variabile o una funzione 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));
questo è il mio approccio per risolvere questo genere. Si estende la risposta di Steve Jessop, eliminando la necessità di impostare gli argomenti di template in modo esplicito e aggiungendo l'opzione di utilizzare anche functoins e puntatori ai metodi (getter)
#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;
}
Dovrai rendere op <() const e passare il suo parametro come riferimento const. –
@Neil, ho pubblicato l'esempio che ho trovato perché non avevo il tempo di digitare tutto tizio. L'IT è stato un esempio solido e ha risolto il problema. Sono contento che ti ci siano voluti 40 minuti per decidere di non farlo. Potrei vederlo essere down-votato se non includessi il sito di origine, ma l'ho fatto. Non è che abbia provato a darlo in pegno come se fosse mio. – Gabe
@Neil Ammetto che è passato un po 'di tempo da quando ho usato C++, ma mi sono ricordato alcune idee generali con questa domanda, ecco perché ho risposto. Non sto affermando che sia perfetto, ma funziona, l'ho provato io stesso. Ho preso il tuo suggerimento e l'ho aggiunto. Se hai qualche altro problema, parla piuttosto agendo in modo accondiscendente. Agire in quel modo non è così, SO riguarda entrambi i tipi. – Gabe