Sort a vector of objects

Hi!

I have several pointers to objects in a vector to be sorted. I think I can use sort(myVector.begin(),myVector.end()) but this method sort by pointer memory directions.

I have an object called Vehicle with an int price. So I'd like to sort the vehicles by price.

Is there any method to use sort and tell it to sort by the objects instead of sorting by the pointers of the vectors ?

Many Thanks!

Enric
EM77Asked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jkrCommented:
>>I have an object called Vehicle with an int price. So I'd like to sort the vehicles by price.

All you need to do is to provide an predicate object that takes care of the comparison, e.g.

class Vehicle {

public:

int GetPrice () const { return price;}

private;

int price;
};

struct greater_VehiclePtr : public greater<Vehicle*> {
public:
  bool operator()(Vehicle* pl, Vehicle* pr) { return pl->GetPrice() > pr->GetPrice(); }
};

vector<Vehicle*> vVehicles;

//...

sort(vVehicles.begin(), vVehicles.end(), greater_VehiclePtr());
EM77Author Commented:
Where do you define the greater_VehiclePtr? Inside the Vehicle hearder??¿?¿?
jkrCommented:
That would be one possible place. As a rule of thumb: Define it where you need it. The following demostrates the whole thing:

#include <vector>
#include <algorithm>
#include <functional>
using namespace std;

class Vehicle {

public:

int GetPrice () const { return price;}

private:

int price;
};

struct greater_VehiclePtr : public greater<Vehicle*> {
public:
  bool operator()(Vehicle* pl, Vehicle* pr) { return pl->GetPrice() > pr->GetPrice(); }
};

int main () {

vector<Vehicle*> vVehicles;

//...

sort(vVehicles.begin(), vVehicles.end(), greater_VehiclePtr());

return 0;
}
CompTIA Security+

Learn the essential functions of CompTIA Security+, which establishes the core knowledge required of any cybersecurity role and leads professionals into intermediate-level cybersecurity jobs.

EM77Author Commented:
Ok, It works!!!!

Now I have another problem. First of all I have to list the objects sorted by price, then I have to list it as they were created.

When I wrote sort(......) my vVector is modified so then I'd like to set it as it was created...

Any idea???

Many Thanks!

Enric
jkrCommented:
>>I have to list it as they were created.

What do you mean?
itsmeandnobodyelseCommented:
That works at my system (VC6/XP):

class A
{
public:
    string a;
    A(const char* s) : a(s) {};

};


bool Aless(const A*& pa1, const A*& pa2)
{
    return pa1->a < pa2->a;
}

class A
{
public:
    string a;
    A(const char* s) : a(s) {};

    static bool less(const A*& pa1, const A*& pa2)
    {
        return pa1->a < pa2->a;
    }
};

int main()
{
    vector<A*> arr;
    A a1("John");
    A a2("James");
    A a3("Bill");
    arr.push_back(&a1);
    arr.push_back(&a2);
    arr.push_back(&a3);
    sort(arr.begin(), arr.end(), A::less);

    for (int ii = 0; ii < arr.size(); ++ii)
        cout << arr[ii]->a << endl;

    return 0;
};

It passes a substitute to the built-in operator< function that could be defined for class types only.

Regards, Alex
itsmeandnobodyelseCommented:
That part needs to removed:

class A
{
public:
    string a;
    A(const char* s) : a(s) {};

};


bool Aless(const A*& pa1, const A*& pa2)
{
    return pa1->a < pa2->a;
}

>>>>  I'd like to set it as it was created...

You need to add a member that counts :

class Vehicle
{
    static int lastCounter;
    int counter;
    int price;
public:
    Vehicle(int pr) : counter(++lastCounter), price(pr) {}
    ...
};


// vehicle.cpp

#include "vehicle.h"

// initialize counter
int Vehicle::lastCounter = 0;


With that you could define a further sort function that goes for counter rather than for price.

Regards, Alex
EM77Author Commented:
First of all I'm adding pointer to vector as I show:

vVehicles.push_back(pVehicle1); //pVehicle->price = 1000
vVehicles.push_back(pVehicle2); //pVehicle->price = 3000
vVehicles.push_back(pVehicle3); //pVehicle->price = 2000

1.-Now I use your code and I list all vehicles in vector so they're showed sorted

pVehicle2
pVehicle3
pVehicle1

2.- Now I need to show all vehicles (without using your sort method) as I pushed_back in vector, so I need to show  as I've created the object.
The result need to be:

pVehicle1
pVehicle2
pVehicle3

But I'm showing it from the first place of the vector to the end and the result is the same as sorted vehicles. I understand that when we sort vehicles we are modifying the vector so when I'm trying to show as I've created the vehicles it is shown incorrect.

Sorry but my english is not as good as I'd like ! ;)

Thanks
itsmeandnobodyelseCommented:
class Vehicle {

public:
  static int lastCounter;

   Vehicle(int pr) : counter(++lastCounter), price(pr) {}

   int GetPrice () const { return price;}

   int GetCount() const  { return counter;}

   static bool lessPrice(const Vehicle*& pv1, const Vehicle*& pv2)
   {
        return pv1.GetPrice() < pv2->GetPrice();
   }
   static bool lessCount(const Vehicle*& pv1, const Vehicle*& pv2)
   {
        return pv1.GetCount() < pv2->GetCount();
   }

private;

    int counter;
    int price;
   
};

int main()
{
     vector<Vehicle*> vVehicles;
     vVehicles.push_back(pVehicle1); //pVehicle->price = 1000
     vVehicles.push_back(pVehicle2); //pVehicle->price = 3000
     vVehicles.push_back(pVehicle3); //pVehicle->price = 2000
     sort<vVehicles.begin(), vVehicles.end(), Vehicle::lessPrice);
     for (int i = 0; i < arr.size(); ++i)
        cout << vVehicles[i]->GetCount() << '|' << vVehicles[i]->GetPrice() << endl;
     sort<vVehicles.begin(), vVehicles.end(), Vehicle::lessCount);
     for (int ii = 0; ii < vVehicles.size(); ++ii)
        cout<< vVehicles[ii]->GetCount()  << '|'   << vVehicles[ii]->GetPrice()  << endl;

    return 0;
};

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
itsmeandnobodyelseCommented:
>>>> int Vehicle::lastCounter = 0;

I forgot to initialize the static member.

Regards, Alex
jkrCommented:
>>Now I need to show all vehicles (without using your sort method) as I pushed_back in vector

Just do that before you sort them or create a copy of the vector, e.g.

vector<Vehicle*> vVehicles;

//...
vector<Vehicle*> vVehiclesInAddingOrder = vVehicles;

sort(vVehicles.begin(), vVehicles.end(), greater_VehiclePtr());
AxterCommented:
I recommend using smart pointers instead of raw dummy pointers in an STL container.

Moreover, if you use the following smart pointer, it will let you sort by the object instead of the object pointer address.
http://axter.com/smartptr

You can declare it like so:

vector<smart_ptr<Vechicle> > vVehicles;

If you which to use a more simplistic smart pointer, you can use the following:
http://code.axter.com/copy_ptr.h

The copy_ptr also has value semantics for the comparison operator instead of pointer semantics.

By using a smart pointer with value semantics, you get safer code, and it makes it easier to do sorting in STL containers.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Editors IDEs

From novice to tech pro — start learning today.