Friday, April 15, 2011

functors_sort:vector

I have this class:

class QSweep{

public:
QSweep(const vector< vector<double> >& myPoints, const vector< vector<int> >&myEdges);

void intersection(vector< vector<double> >& myPoints, vector< vector<int> >& myEdges);
vector< vector<int> >* sortEdges(vector< vector<double> >& myPoints,
vector<vector<int>>& myEdges);

bool sortx(const vector< vector<int> >& edge1, const vector< vector <int> >& edge2) {
return edge1[0][0]< edge2[0][0];
};
private:
vector< vector<double> > myPoints_;
vector< vector<int> > myEdges_;
};

The constructor creates the desired data structure in this way:

QSweep::QSweep(const vector< vector<double> >& myPoints, const vector< vector<int>>&  
myEdges){
myPoints_=vector< vector<double> > (myPoints.size(), vector< double >(3,0));
for (unsigned int i=0;i<myPoints.size();i++){
myPoints_[i][0]=myPoints[i][0];
myPoints_[i][1]=myPoints[i][1];
myPoints_[i][2]=myPoints[i][2];
}

myEdges_=vector< vector<int> > (myEdges.size(), vector< int >(2,0));
for (unsigned int i=0;i<myEdges.size();i++){
myEdges_[i][0]=myEdges[i][0];
myEdges_[i][1]=myEdges[i][1];
}
}

giving E.g: myPoints={{1.0,1.0,2.0},{18.0,4.0,2.0},{5.0,1.0,2.0}}; myEdges={{0,1},{1,2},{0,2}};

I want to have a sort function for myEdges 2-dimensional vector depending on the first coordinate of myPoints given by myEdges[i][0].E.g after sorting myEdges would become myEdges={{0,1},{0,2},{1,2}} because myPoints[myEdges[1][0]][0]

I tried:

 bool sortx(const vector<int> & edge1,const vector<int> & edge2) {
 return myPoints_[edge1[0][0]< myPoints_[edge2[0][0];
 };

in the public member of QSweep with the call:

int main(){
...
sort(myVector1.begin(),myVector1.end(),sortx);
}

but I keep having the same error (even if I modified something): sort.cpp: In static member function 'static bool QSweep::sortx(const std::vector >&, const std::vector >&)': sort.cpp:47: error: invalid use of member 'QSweep::myPoints_' in static member function sort.cpp:25: error: from this location sort.cpp:47: error: invalid use of member 'QSweep::myPoints_' in static member function sort.cpp:25: error: from this location sort.cpp: In function 'int main()': sort.cpp:106: error: 'sortx' was not declared in this scope

Then I tried to write a functor for my class (which I never worked with before): The functor is:

class order{
public:
QSweep* o;
//vector< vector<double> > myPoints_;
bool operator() (const vector<int>& edge1, const vector<int>& edge2){
return o->myPoints_[edge1[0]][0]<o->myPoints_[edge2[0]][0];
}
};

and I defined it outside the Class QSweep. And I call the functor in the main program as:

sort(myVector1.begin(),myVector1.end(),order());

The program compiles but I get an bus error message: ./sort 1 2 2 3 1 3 Bus error

oii so definitely my functor is not good.. should I initialize the object of class QSweep somehow. I do not understand how this functor will know to use exactly myPoints_ elements from QSweep class..

thank you in advance, madalina

From stackoverflow
  • sort(myVector1.begin(),myVector1.end(),sortx);

    You need to tell std::sort, which you are using inside main, if you are going to use this form, that you want to use the member function sortx. Try:

    sort(myVector1.begin(),myVector1.end(), std::mem_fun_ref(&QSweep::sortx));
    

    Also, your sort function takes incorrect parameters:

    bool sortx(const vector< vector >& edge1, const vector< vector >& edge2)

    To sort your vector of vector of ints your sortx should take:

    bool sortx(const vector<int>& edge1, const vector<int>& edge2)
    

    Also, note that you cannot use multiple indexes with a vector of vector as you can with multidimensional arrays. I think you have over complicated your problem :)

    Here is a simplified solution for sorting your tuple Point type:

    #include <iostream>
    
    #include <iterator>
    #include <algorithm>
    #include <vector>
    
    using namespace std;
    
    template <class _MyType>
    struct Point  {
        Point() {}
    
        void insert(_MyType const& p) { 
            _pts.push_back(p); 
        }
    
        bool operator<(Point<_MyType> const& o) {
            return _pts[ 0 ] < o._pts[ 0 ];
        }
    
    private:
        typename vector<_MyType> _pts;
    };
    
    int main()
    {
        Point<int> p;
        p.insert(1); p.insert(0); p.insert(2); // {1, 0, 2}
        Point<int> q;
        q.insert(-1); q.insert(10); q.insert(2); // {-1, 10, 2}
        vector<Point<int> > sweep;
        sweep.push_back(p);
        sweep.push_back(q);
        sort(sweep.begin(), sweep.end());    
    
        return 0;
    }
    
  • At first sight, from your text, it seems that static bool QSweep::sortx(...) makes invalid use of this data members. This explains the compiler error. Note that in the source code you provided, the function isn't static.

    At second sight, you cannot define an incomplete ordering to std::sort: if you say "I don't care if my second member is bigger or smaller, if the first one is bigger, the whole object is bigger", you leave the sort algorithm in the void for values that have equal first members.

    That's why sort takes a strict weak ordering. You have to define the order for values with an equal first member, too.

  • what do you mean you dont access vector of vector with indexes? But how can I access then the elements? or how I could initializa the vectors of vectors? with push_back?or?

    the problem is that the function:

    static bool sortx(const vector<int>& edge1,const vector<int> &  edge2)  {
     return edge1[0]< edge2[0];
      };
    

    with the call: sort(myVector1.begin(),myVector1.end(),&QSweep::sortx);

    it is working, but I want another criteria for sorting my edges:

      myPoints_[edge1[0]][0]< myPoints_[edge2[0]][0];
    

    and this I do not know how to do as I use here a member myPoints_ of QSweep. This is why I tried the functor:

    class order{
    public:
    QSweep* o;
    bool operator() (const vector<int>& edge1, const vector<int>& 
    
        edge2){
     return o->myPoints_[edge1[0]]
    
              [0]<o->myPoints_[edge2[0]][0];
    }
    };
    

    but definitely is wrong.. thank you in advance, madalina

  • Your order functor is the right way do go; it just seems you have omitted to initialize its o member.

    Have you tried:

    class order{
    public:
      QSweep* o;
      order(QSweep* o_) : o(o_) {}
      bool operator() (const vector<int>& edge1, const vector<int>& edge2){
        return o->myPoints_[edge1[0]][0]<o->myPoints_[edge2[0]][0];
      }
    };
    
    sort(myVector1.begin(),myVector1.end(),order(qsweep));
    

    The comparison function is OK, sort doesn't require all elements to compare greater or less than others.

  • qsweep is an object of the QSweep class the one initialized in the program no. I use in my main program:

    ....
    QSweep* s= new QSweep(myVector, myVector1);
    ....
    

    Using so this initialization for o in the class order, the program compiles and runs with the call:

    sort(myVector1.begin(),myVector1.end(),order(s));
    

    And the sorting is performed only in regard to the first components of myPoints_ (as I really needed to do) for this sweep algorithm.

    thank you very much for your help! (I was starting to be really confused), madalina

    dirkgently : If you find jpalecek's answer helpful, please accept his answer.

0 comments:

Post a Comment

Note: Only a member of this blog may post a comment.