#c
#c
Вопрос:
Код отсортирует std::pair на основе первых элементов, а затем второго (если первые элементы равны).
Кто-нибудь может показать мне, как я мог бы отсортировать на основе третьего элемента, используя кортеж? если первое и второе совпадают?
Что хотелось бы знать, так это как использовать предикат для сортировки на основе первого, затем второго (если первое равно), затем третьего (если первое и второе равны)?
Например, если бы у меня было:
(3,2,3)
(1,1,0)
(1,1,1)
(2,2,2)
Это напечатало бы:
(1,1,0)
(1,1,1)
(2,2,2)
(3,2,3)
Код:
#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>
typedef std::pair<double, double> my_pair;
struct sort_pred
{
bool operator ()( const my_pair amp;left, const my_pair amp;right ) const
{
return ( left.first < right.first ) ||
( !( right.first < left.first ) amp;amp; ( right.second > left.second ) );
}
};
int main()
{
std::vector<my_pair> data;
data.push_back( my_pair( 3, 2 ) );
data.push_back( my_pair( 1, 2 ) );
data.push_back( my_pair( 1, 1 ) );
data.push_back( my_pair( 2, 2 ) );
std::stable_sort( data.begin(), data.end(), sort_pred() );
for ( const auto amp;p : data ) std::cout << p.first << ' ' << p.second << std::endl;
}
Комментарии:
1. поместить их в
std::tuple
, а потом позвонитьstd::sort
?2. Вы пробовали сортировать
vector<tuple<int,int,int>>
без предиката и посмотреть, что получится?3. …нравится это ?
4. @TedLyngmo согласился. Похоже, вопрос нуждается в деталях или ясности.
5. @user12660947 Зачем вам вообще нужен предикат?
std::pair
иstd::tuple
ужеoperator<
реализовано сравнение значений так, как вы описываете. Так что плохого в том, чтобы позволитьstd::sort()
выполнять сортировку по умолчанию без использования пользовательского предиката?
Ответ №1:
Что хотелось бы знать, так это как использовать предикат для сортировки на основе первого, затем второго (если первое равно), затем третьего (если первое и второе равны)?
У std::tuple
уже есть operator<
, который выполняет вышеуказанное, но чтобы сделать это вручную, люди в основном используют для этого std::tie
, который сам создает кортеж из предоставленных аргументов. Тогда функтор сравнения для класса с тремя полями ( f1
— f3
) мог бы быть:
[](autoamp; a, autoamp; b) { return std::tie(a.f1, a.f2, a.f3) < std::tie(b.f1, b.f2, b.f3); }
Чтобы показать что-то другое, предположим, что вы хотите порядок сортировки по возрастанию для первых двух полей, но порядок убывания для последнего поля.
Обратите внимание, что я поменял местами a
и b
в std::get<2>
:
auto comp = [](autoamp; a, autoamp; b) {
return
std::tie(std::get<0>(a), std::get<1>(a), std::get<2>(b))
<
std::tie(std::get<0>(b), std::get<1>(b), std::get<2>(a));
};
std::sort(data.begin(), data.end(), comp);
Это дало бы вам такой приказ:
1,1,1
1,1,0
2,2,2
3,2,3
Поменяйте местами a
и b
in std::get<2>
обратно, и вы получите тот же порядок, что и в вашем исходном кортеже, который уже встроен.
Если вы хотите сделать это без помощи std::tie
, вы могли бы сделать это следующим образом:
struct sort_pred {
bool operator ()(const my_tupleamp; left, const my_tupleamp; right) const {
if(std::get<0>(left) != std::get<0>(right))
return std::get<0>(left) < std::get<0>(right);
if(std::get<1>(left) != std::get<1>(right))
return std::get<1>(left) < std::get<1>(right);
return std::get<2>(left) < std::get<2>(right);
}
};
Или, если вы хотите, чтобы это было с большим количеством троичных операторов, вы тоже можете это сделать. Я нахожу это немного более трудным для чтения, но, думаю, это дело вкуса:
struct sort_pred {
bool operator ()(const my_tupleamp; left, const my_tupleamp; right) const {
return
std::get<0>(left) != std::get<0>(right) ? std::get<0>(left) < std::get<0>(right) :
std::get<1>(left) != std::get<1>(right) ? std::get<1>(left) < std::get<1>(right) :
std::get<2>(left) < std::get<2>(right);
}
};
Комментарии:
1. Альтернативное предложение: просто используйте
std::tuple
для начала вместоstd::tie
2. @MooingDuck Да, я действительно не знаю, есть ли плюсы и минусы в том, чтобы делать это так или иначе.
std::tie
коротко, так что это бонус. 🙂