I am trying to sort a person vector by person.name and age. Therefore, I tried to override the operator<
in the Person
definition, and to use functor with std::sort()
.
However, I did not get what I want. My expectation is that Persons are first ordered by their name, and then by their age. But I get the same result with both solutions:
che is less than xu
(wu, 30)
(che, 34)
(xu, 21)
What I expect order is:
(che, 34)
(wu, 30)
(xu, 21)
Could anyone help point the mistake I made? Thanks
The source code is:
class Person{
public:
string _name;
int _age;
public:
Person(string name, int age):_name(name),_age(age){
}
bool operator<(const Person* b) const {
cout<<"Expect "<<_name <<b->_name <<" "<< (_name < b->_name)<<endl;
if(_name != b->_name) {
return _name < b->_name;
}
else return _age<b->_age;
}
bool operator<(const Person& b) const {
if(_name!=b._name) {
cout<<_name <<" is less than "<<b._name<<endl;
return _name<b._name;
} else return _age<b._age;
}
friend ostream& operator<<(ostream& out, const Person& b) {
out << "(" << b._name << ", " << b._age << ")"<<endl;
return out;
}
};
bool PersonCompare(const Person* a, const Person* b ){
cout<<"Expect "<<a->_name <<b->_name <<" "<< (a->_name < b->_name)<<endl;
if(a->_name != b->_name) {
return a->_name < b->_name;
}
else return a->_age<b->_age;
}
class PersonPrint{
public:
PersonPrint(){
}
void operator()(const Person& person){
cout<<person;
}
void operator()(const Person* person){
cout<<*person;
}
};
void testSort(){
vector<Person*> personsList;
personsList.push_back(new Person("xu", 12));
personsList.push_back(new Person("che", 23));
personsList.push_back(new Person("sxy", 34));
/*std::sort(personsList.begin(), personsList.end(), [](Person* a, Person* b ){
if(a->_name!=b->_name) return a->_name<b->_name;
else return a->_age<b->_age;
}); *///This works
/* std::sort(personsList.begin(), personsList.end(), PersonCompare ) *///This works..
std::sort(personsList.begin(), personsList.end()); //This does not work
for_each(personsList.begin(), personsList.end(), PersonPrint());
}
==============
It is the logic error inside of lambda/operator. After changing if(a._name<b._name)
to if(a._name!=b._name)
, the error is fixed.
/////////////////////////////////////
I updated the code.
Add bool operator<(const Person* b) const{}
for class Person
, and then try to sort a vector of Person*
. But the result is not sorted as I expected, and the newly added operator<(const Person*)
is not called. Any suggestion here? Thanks
Your comparison function is treading the territories of undefined behavior. No surprise you are not seeing what you expect. From std::sort's documentation
comp - comparison function object (i.e. an object that satisfies the requirements of Compare) which returns true if the first argument is less than (i.e. is ordered before) the second.
Requirements of Compare:
The return value of the function call operation applied to an object of type Compare, when contextually converted to bool, yields true if the first argument of the call appears before the second in the strict weak ordering relation induced by this Compare type, and false otherwise.
Your comparison function doesn't meet the criteria of strict week ordering.
You can simply do:
std::sort(persons.begin(), persons.end(),
[](const Person& a, const Person& b) { return std::tie(a.name, a.age) < std::tie(b.name, b.age); })
I have written an article on this: https://isocpp.org/blog/2016/05/strict-weak-ordering-and-stl which you may want to refer.
Edit(Based on OP's edit):
This doesn't works because you have provided member functions for Person
class whereas the type on which you want to call is Person*
. Both are different types.
You will have to move the PrintPerson
function's definition outside the class and make it declare as a friend method in Person class. Unfortunately you cannot do the same with the bool operator<(Person *a, Person *b)
because operator overloading doesn't works with pointer types. Your only alternative is to pass a comparer.