Сортировать с переопределением оператора не получается я хочу
Я пытаюсь отсортировать человека вектор по person.name и возрасту. Поэтому я попытался переопределить operator<
в Person
определение, и использовать функтор с std::sort()
,
Однако я не получил то, что хочу. Я ожидаю, что люди сначала упорядочены по имени, а затем по возрасту. Но я получаю одинаковый результат с обоими решениями:
che is less than xu
(wu, 30)
(che, 34)
(xu, 21)
Я ожидаю, что заказ:
(che, 34)
(wu, 30)
(xu, 21)
Может ли кто-нибудь помочь указать на ошибку, которую я сделал? Спасибо
Исходный код:
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());
}
============== Это логическая ошибка внутри лямбда / оператора. После изменения if(a._name<b._name)
в if(a._name!=b._name)
, ошибка исправлена.
/////////////////////////////////////
Я обновил код. добавлять bool operator<(const Person* b) const{}
для класса Person
, а затем попробуйте отсортировать вектор Person*
, Но результат не отсортирован, как я ожидал, а недавно добавленный operator<(const Person*)
не называется. Любое предложение здесь? Спасибо
1 ответ
Ваша функция сравнения состоит в неопределенном поведении. Не удивительно, что вы не видите того, что ожидаете. Из документации std::sort
comp - объект функции сравнения (т. е. объект, который удовлетворяет требованиям Compare), который возвращает true, если первый аргумент меньше (т.е. упорядочен раньше) второго.
Требования сравнения:
Возвращаемое значение операции вызова функции, примененной к объекту типа Compare, когда контекстно преобразуется в bool, возвращает true, если первый аргумент вызова появляется перед вторым в строгом слабом порядке упорядочения, вызванном этим типом Compare, и false в противном случае,
Ваша функция сравнения не соответствует критериям строгого недельного заказа.
Вы можете просто сделать:
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); })
Я написал статью об этом: https://isocpp.org/blog/2016/05/strict-weak-ordering-and-stl которую вы можете сослаться.
Изменить (на основе редактирования ОП):
Это не работает, потому что вы предоставили функции-члены для Person
класс, тогда как тип, который вы хотите вызвать Person*
, Оба разных типа. Вам придется переместить PrintPerson
определите функцию вне класса и сделайте так, чтобы она объявлялась как метод друга в классе Person. К сожалению, вы не можете сделать то же самое с bool operator<(Person *a, Person *b)
потому что перегрузка оператора не работает с типами указателей. Ваша единственная альтернатива - пройти сравнение.