2010-02-20 7 views
5

Quiero ordenar vector points_vec como se muestra en el pseudocódigo a continuación. Quiero resolver este vector, por un valor de coordenadas como X o Y o Zvector de ordenación con puntos 3D por un valor de coordenadas - sintaxis

class A{ 

    std:vector<double*> points_vec; 

    void doSomething(); 

} 

Luego, en el método A::doSomething, quiero resolver este vector:

void A::doSomething() { 
    std::sort(points_vec.begin(), points_vec.end(), sortPoints()); 
} 

Puede alguien por favor me muestran la sintaxis para el sortPoints() método ... Preferiblemente quiero que sea un método de la clase A. this post crea un struct para hacer esto, no estoy seguro de si debería crear un struct similar dentro de la clase. ¿Hay alguna otra manera de manejar esto?

gracias

+0

Te harías un favor si usas una clase para representar tus puntos. Algo como esto: http://ogre.svn.sourceforge.net/viewvc/ogre/trunk/OgreMain/include/OgreVector3.h?revision=9491&view=markup. – Manuel

Respuesta

5

Usted tiene dos opciones para ordenar: pase una función/functor a sort o defina operator< para su clase. Ahora, su clase A parece ser más un envoltorio para un conjunto de coordenadas. Entonces, crea otra clase para tus coordenadas.

struct Point { 
    double x_, y_, z_; 
    Point(double x, double y, double z) : x_(x), y_(y), z_(z) {}    
    // just an example, you can refine the following as much as you need 
    bool operator<(Point const& other) { 
     return x < other.x; 
    } 
}; 

bool sortOnY(Point const& l, Point const& r) const { 
     return l.y < r.y; 
} 

class A { 
    std::vector<Point> pts_; 
    void doSomething() { 
      sort(pts_.begin(), pts_.end()); 
    } 
    // if sorting on y is also required, you will need 
    // to use a custom comparator which can be either 
    // a functor or a function 
    void doSomeOtherThing() { 
     sort(pts_.begin(), pts_.end(), sortOnY); 
    } 
};   
+1

+1 - Pero no creo que sea una buena idea ordenar por x de manera predeterminada, los vectores no tienen un orden natural e imponer uno puede ser confuso.Probablemente sea mejor definir tres funciones ('sortOnX/Y/Z' y dejar que el usuario diga explícitamente cuál quiere. – Manuel

+0

@Manuel: 1) El código publicado aquí intenta retocar todas las posibilidades. 2) El 'op <' se define en los puntos y no en el 'vector' - esa es una opción de diseño. 3) La elección del contenedor es algo que habría comentado, pero omitido, en estos casos elegiría un contenedor ordenado que uno de acceso aleatorio. – dirkgently

+0

@dirkgently - Quise decir vector como en 'vector 3D' lo siento por la confusión. Debería haber dicho 'Point' – Manuel

2

En primer lugar - lo que tiene romperá todos sus puntos - como podrá ordenar por dobles individuales y no por puntos "que consta de 3 dobles".

La mejor manera de hacer esto creo que es:

  1. Almacenar los puntos como alguna clase Point3D no un par de dobles
  2. Definir el operador de menos de Point3D
  3. Sólo tiene que llamar std :: sort (points_vec.begin(), points_vec.end());

Si desea ordenarlos de diferentes maneras, es cuando usaría el funtor de clasificación y crearía funtores diferentes con operadores() para diferentes propósitos.

+0

@RnR: Gracias por la respuesta. Agradecería que pudieras publicar una sintaxis, por ej. sintaxis por menos que el operador. ¿Cuál será la sintaxis si continúo usando double *? – memC

+0

¡Gracias por su sugerencia! Implementaré la clase Point para manejar esto. Sugerencia muy útil. – memC

5

La manera más simple es proporcionar un functor que se utiliza con el algoritmo sort para comparar dos valores. Se puede escribir así:

struct Compare 
{ 
    bool operator()(double* first, double* second) const 
{ 
    //Compare points here 
} 
}; 

Y utilizar como:

std::sort(p.begin(), p.end(), Compare()); 

EDITAR para hacer comentarios por OP: Sí, este código de ejemplo compila bien:

class A 
{ 
public: 
    struct c 
    { 
     bool operator()(int a, int b) const 
     { 
      return a < b; 
     } 
    }; 
}; 
int main() 
{ 
    std::vector<int> a1; 
    a1.push_back(2); 
    a1.push_back(1); 
    std::sort(a1.begin(), a1.end(), A::c()); 

    return 0; 
} 
+0

Esto responde la pregunta directamente pero ... es imposible que funcione correctamente de esta manera;) (romperá todos los puntos si ordena el vector por dobles individuales) – RnR

+0

@Naveen: supongo que esta 'struct Compare' puede descansar dentro de la clase A. ¿Correcto? – memC

+0

@RnR, Naveens 'operator()' toma punteros a dobles, asumiendo matrices dinámicas. –

1

Si desea ordenar por x o y o z, esos son tres funcionalidades diferentes. Para qué ordenar es información adicional que realmente no viene de std::sort. Necesitas tener un objeto para pasarlo.

struct coord_comparison { 
    int coord_id; // <= critical information 
    bool operator()(double (*l)[3], double (*r)[3]) { 
     return (*l)[ coord_id ] < (*r)[ coord_id ]; 
    } 
    coord_comparison(int id) { coord_id = id; } 
}; 

Crear esta estructura dentro de su clase o en el exterior, pero es necesario que haya una estructura y no una función libre, y operator() no puede ser estática.Llamar:

std::sort(points_vec.begin(), points_vec.end(), compare_points(1 /*for y*/)); 

Clasificación por los 3 coords a la vez:

Usted tiene

std:vector<double*> points_vec; 

Voy a suponer que los double* apunta a un array de 3 coordenadas. Esto es más limpio:

std:vector<double(*)[3]> points_vec; 

std::sort 's tercer argumento es un funtor que compara dos secuencia de objetos:

bool compare_coords(double(*l)[3], double(*r)[3]) { 

Afortunadamente, la comparación de dos secuencias ya se codifica para usted por std::less:

return std::less(*l, *l + (sizeof *l/sizeof **l), r); 

(tal vez hice más trabajo de lo necesario para obtener el tamaño de la matriz)

return std::less(*l, *l + 3, r); 
} 

Esta función puede ser útil fuera de la clase, por lo que sería una función gratuita. Debe hacerlo static si va a permanecer dentro de la clase.

Por último, dejar fuera de los parens cuando se pasa a la función std::sort:

std::sort(points_vec.begin(), points_vec.end(), compare_points); 
+0

@Potatoswatter: +1: Gracias por una respuesta detallada ... y gracias por la nota sobre hacerlo ** estático ** – memC

2

No creo que este hilo estaría completa sin una mención de Boost.Bind:

struct Point3D { 
    double x, y; 
    Point3D(double x=0., double y=0.) : x(x), y(y) { 
    } 
}; 

int main() { 

    std::vector<Point3D> points; 
    points.push_back(Point3D(-1., 2.)); 
    points.push_back(Point3D(2., -1.)); 
    points.push_back(Point3D(-2., 0.)); 

    using boost::bind; 
    std::sort(points.begin(), points.end(), 
       bind(&Point3D::x, _1) < bind(&Point3D::x, _2)); 
    // points sorted by x coord 

    std::sort(points.begin(), points.end(), 
       bind(&Point3D::y, _1) < bind(&Point3D::y, _2)); 
    // points sorted by y coord 
} 

Qué pena std::tr1::bind no es compatible. Pero, por supuesto, con un compilador C++ 0x podrá hacer esto:

std::sort(points.begin(), points.end(), 
      [](Point3D const & a, Point3D const & b) { return a.x < b.x; }); 
Cuestiones relacionadas