Я хочу отсортировать вектор date
s и я написал функцию сравнения для него:
#include <iostream>
struct date {
int day;
int month;
int year;
};
int compare_dates(date a, date b) {
if (a.year < b.year) {
return -1;
} else if (a.year == b.year) {
if (a.month < b.month) {
return -1;
} else if (a.month == b.month) {
if (a.day < b.day) {
return -1;
} else if (a.day > b.day) {
return 1;
}
} else {
return 1;
}
} else {
return 1;
}
return 0;
}
int main() {
date a = {};
date a.day = 19;
date a.month = 11;
date a.year = 2016;
date b = {};
date b.day = 20;
date b.month = 11;
date b.year = 2016;
compare_dates(a, b) // -1
compare_dates(b, a) // 1
compare_dates(b, b) // 0
return 0;
}
Работает хорошо, но compare_dates
Функция выглядит ужасно. Есть ли идея, как я могу улучшить это?
Я не эксперт по С ++, а другие указывают, что std::sort()
не требует трехстороннего сравнения, только <
, Но чтобы очистить ваш код как написано:
Ваш compare_dates()
продолжает делать трехсторонние сравнения для >/</==
и хочет +1/-1/0
возвращаемое значение Итак, объявляем трехсторонний cmp()
вспомогательная функция, которая делает это, как мы делаем в Python. Теперь ваш код сводится к:
int cmp(int x, int y) {
return (x>y) ? 1 : ((x<y) ? -1 : 0);
}
int compare_dates(date a, date b) {
if (cmp(a.year, b.year) != 0)
return cmp(a.year, b.year);
if (cmp(a.month, b.month) != 0)
return cmp(a.month, b.month);
return cmp(a.day, b.day);
}
Вы можете выполнить сравнение более низкого порядка только в том случае, если сравнение более высокого порядка дало ‘==’. Таким образом, это позволяет вам избегать всех других выражений, скобок и отступов, что поддерживает постоянный уровень отступа и не вызывает проблем. Это также вызывает симметрию вычислений.
Этого будет достаточно для сортировки контейнеров дат в порядке возрастания:
bool compareDates(date const& lhs, date const& rhs) const {
if(lhs.year == rhs.year) {
if(lhs.month == rhs.month) {
return lhs.day < rhs.day;
}
return lhs.month < rhs.month;
}
return lhs.year < rhs.year;
}
// sort(dates, dates + n, compareDates);
Я намеренно не справился -1
отдельно как для переопределения компаратора контейнеров STL типа std::sort()
, priority_queue
или же std::set
нам не нужно предоставлять целочисленный код возврата и делать код достаточно сложным. Булева достаточно.
Как насчет использования того факта, что в день используется только 4 бита, а в месяц только 5?
#include <iostream>
struct date
{
int day;
int month;
int year;
};
int compare_dates (date a, date b)
{
long da { (a.year << 9) + (a.month << 4) + a.day };
long db { (b.year << 9) + (b.month << 4) + b.day };
return da < db ? -1 : (da > db);
}
int main()
{
date a = { 19, 11, 2016 };
date b = { 20, 11, 2016 };
std::cout << compare_dates(a, b) << std::endl; // print -1
std::cout << compare_dates(b, a) << std::endl; // print 1
std::cout << compare_dates(b, b) << std::endl; // print 0
return 0;
}
— РЕДАКТИРОВАТЬ —
Как указал Кристиан Хакл, этот кодекс немного неясен.
Я надеюсь, что это может быть более понятным, если вы переведете часть битового поля в date
структура, трансформируя его в union
,
Таким образом, вы можете инициализировать отдельный year
, month
а также day
компоненты и использовать full
Компонент для сравнения.
Что-то следующее
#include <iostream>
union date
{
struct
{
unsigned long day : 5U;
unsigned long month : 4U;
unsigned long year : 23U;
} s ;
unsigned long full;
};
int compare_dates (date const & a, date const & b)
{ return a.full < b.full ? -1 : (a.full > b.full); }
int main()
{
date a = { { 19, 11, 2016 } };
date b = { { 20, 11, 2016 } };
std::cout << compare_dates(a, b) << std::endl; // print -1
std::cout << compare_dates(b, a) << std::endl; // print 1
std::cout << compare_dates(b, b) << std::endl; // print 0
return 0;
}