2010-05-03 14 views
56

me gustaría ordenar una vector¿Cómo ordenar un vector STL?

vector<myClass> object; 

Dónde myclass contiene muchos int variables. ¿Cómo puedo ordenar mi vector en cualquier variable de datos específicos de myClass.

Respuesta

61

Sobrecargue menos que el operador, luego ordene. Este es un ejemplo que encontré fuera de la 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()); 

Fuente: here

+13

Querrá hacer op <() const, y pasar su parámetro como referencia constante. –

+15

@Neil, publiqué el ejemplo que encontré porque no tuve tiempo de escribirlo todo tipo. Fue un buen ejemplo y resolvió el problema. Me alegro de que haya tardado 40 minutos en decidirse, votarlo. Pude ver que se votó negativamente si no incluí el sitio de origen, pero lo hice. No es como si hubiera tratado de empeñarlo como propio. – Gabe

+7

@Neil Admitiré que ha pasado un tiempo desde que utilicé C++, pero recordé algunas ideas generales con esta pregunta, por eso respondí. No pretendo que sea perfecto, pero funciona, lo probé yo mismo. Tomé tu sugerencia y la agregué. Si tienes algún otro problema con eso, habla en lugar de actuar de manera condescendiente. Actuar de esa manera no fue así SO se trata de cualquier tipo. – Gabe

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

donde, pred() es un objeto de función que define el orden en los objetos de myclass. Alternativamente, puede definir myclass::operator<.

Por ejemplo, se puede pasar un lambda:

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

O si le pegan con C++ 03, el enfoque objeto de función (v es el elemento sobre el que desea ordenar):

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

@NativeCoder eso es lo que el operador es para - se puede definir como quiera y de acuerdo con la variable que desee. se llama Sobrecarga del operador http://www.cs.caltech.edu/courses/cs11/material/cpp/donnie/cpp-ops.html. –

+8

El enfoque de predicados es bastante mejor que el enfoque de sobrecarga del operador si no tiene un orden genérico de esta clase en particular, pero solo desea ordenarlo para este vector. –

14

Un puntero a miembro le permite escribir un único comparador, que puede funcionar con cualquier miembro de datos de la clase :

#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"; 
} 

salida:

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

Hola Steve, he estado pensando en resolver el mismo problema que esta pregunta sin mucho progreso. Tu solución se ve muy bien para mí. ¡Creo que me habría llevado mucho tiempo encontrarlo, si es que alguna vez lo hubiera hecho! He leído Myers 'Effective C++ & Effective STL y Dewhurst's C++ Common Knowledge. Me pregunto si podrías recomendar algo más de lectura, ¿conoces algún libro que cubra ejemplos como el que acabas de describir en particular o, en su defecto, sugerencias más generales que me ayuden a ver soluciones como esa? –

+1

@Czarak: mirándolo de nuevo, probablemente podría mejorarse. Por ejemplo, podría optimizar mejor si el puntero al miembro fuera un parámetro de plantilla: 'plantilla estructura CompareByMember2 {operador bool() (const T & lhs, const T & rhs) {return lhs. * F

+0

@Czarak: en cuanto a la lectura, no estoy seguro. El "truco" aquí es la combinación de punteros de miembro con plantillas, creo que es cuestión de estar cómodos escribiendo plantillas y sabiendo qué se puede hacer con ellas. El libro de Vandevoorde & Josuttis "Plantillas en C++: la guía completa" se supone que es bueno, pero no lo he leído. Puede ser lo suficientemente viejo y caro como para que haya una mejor opción por ahora. Mire http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list. ¡Y tenga en cuenta que si tiene C++ 0x, una función lambda puede superar la escritura de toda la clase para esto! –

8

Como se explica en otras respuestas que necesita para pro vide una función de comparación. Si desea mantener la definición de esa función cerca de la llamada sort (por ejemplo, si solo tiene sentido para este tipo), puede definirla allí con boost::lambda. Use boost::lambda::bind para llamar a la función miembro.

Para, por ejemplo ,. ordenar por variable miembro o función 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)); 
2

esta es mi enfoque para resolver este general. Se extiende la respuesta de Steve Jessop al eliminar el requisito de establecer argumentos de plantilla de forma explícita y añadiendo la opción de utilizar también functoins y punteros a métodos (captadores)

#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; 
} 
Cuestiones relacionadas