Jeśli mam wektor par:
std::vector<std::pair<int, int> > vec;
Czy istnieje łatwy sposób sortowania listy w kolejności rosnącej na podstawie drugiego elementu pary?
Wiem, że mogę napisać mały obiekt funkcyjny, który wykona pracę, ale czy istnieje sposób na użycie istniejących części STL i std::less
wykonanie tej pracy bezpośrednio?
EDYCJA: Rozumiem, że mogę napisać oddzielną funkcję lub klasę, która będzie przekazywana do trzeciego argumentu do sortowania. Pytanie brzmi, czy mogę go zbudować ze standardowych rzeczy. Naprawdę chciałbym coś, co wygląda jak:
std::sort(vec.begin(), vec.end(), std::something_magic<int, int, std::less>());
Odpowiedzi:
EDYCJA : używając c ++ 14, najlepsze rozwiązanie jest bardzo łatwe do napisania dzięki lambdom, które mogą teraz mieć parametry typu
auto
. To moje obecnie ulubione rozwiązaniestd::sort(v.begin(), v.end(), [](auto &left, auto &right) { return left.second < right.second; });
Po prostu użyj niestandardowego komparatora (jest to opcjonalny trzeci argument do
std::sort
)struct sort_pred { bool operator()(const std::pair<int,int> &left, const std::pair<int,int> &right) { return left.second < right.second; } }; std::sort(v.begin(), v.end(), sort_pred());
Jeśli używasz kompilatora C ++ 11, możesz napisać to samo używając lambd:
std::sort(v.begin(), v.end(), [](const std::pair<int,int> &left, const std::pair<int,int> &right) { return left.second < right.second; });
EDYTUJ : w odpowiedzi na zmiany w Twoim pytaniu, oto kilka przemyśleń ... jeśli naprawdę chcesz być kreatywny i móc wielokrotnie wykorzystywać tę koncepcję, po prostu utwórz szablon:
template <class T1, class T2, class Pred = std::less<T2> > struct sort_pair_second { bool operator()(const std::pair<T1,T2>&left, const std::pair<T1,T2>&right) { Pred p; return p(left.second, right.second); } };
wtedy też możesz to zrobić:
std::sort(v.begin(), v.end(), sort_pair_second<int, int>());
lub nawet
std::sort(v.begin(), v.end(), sort_pair_second<int, int, std::greater<int> >());
Chociaż szczerze mówiąc, to wszystko jest trochę przesadzone, po prostu napisz funkcję 3-liniową i skończ z tym :-P
źródło
operator<
inpair<T1,T2>
. Domyślny komparator używa zarówno pierwszego, jak i drugiego elementu (w przypadku, gdy pierwsze są równe). Tutaj używany jest tylko drugi."is there and easy way to sort the list in increasing order based on the second element of the pair?"
Możesz użyć wzmocnienia w ten sposób:
std::sort(a.begin(), a.end(), boost::bind(&std::pair<int, int>::second, _1) < boost::bind(&std::pair<int, int>::second, _2));
Nie znam standardowego sposobu na zrobienie tego równie krótkiego i zwięzłego, ale możesz złapać
boost::bind
to wszystko składa się z nagłówków.źródło
To całkiem proste, gdy używasz funkcji sortowania z algorytmu i dodajesz własną funkcję porównującą
vector< pair<int,int > > v; sort(v.begin(),v.end(),myComparison);
Teraz musisz dokonać porównania na podstawie drugiego wyboru, więc zadeklaruj jako „mojePorównanie” jako
bool myComparison(const pair<int,int> &a,const pair<int,int> &b) { return a.second<b.second; }
źródło
W C ++ 0x możemy użyć funkcji lambda:
using namespace std; vector<pair<int, int>> v; . . sort(v.begin(), v.end(), [](const pair<int, int>& lhs, const pair<int, int>& rhs) { return lhs.second < rhs.second; } );
W tym przykładzie zwracany typ
bool
jest niejawnie wywnioskowany.Zwracane typy lambda
Gdy funkcja lambda ma pojedynczą instrukcję, a jest to instrukcja powrotu, kompilator może wydedukować zwracany typ. Z C ++ 11, §5.1.2 / 4:
Aby jawnie określić zwracany typ, użyj formularza
[]() -> Type { }
, takiego jak:sort(v.begin(), v.end(), [](const pair<int, int>& lhs, const pair<int, int>& rhs) -> bool { if (lhs.second == 0) return true; return lhs.second < rhs.second; } );
źródło
if (lhs.second == 0)
?lhs.second < rhs.second
może zwrócićtrue
lubfalse
i kompilator może jasno wywnioskowaćbool
. Chciałem tylko zademonstrować[]() -> Type { }
sprawę.Na coś wielokrotnego użytku:
template<template <typename> class P = std::less > struct compare_pair_second { template<class T1, class T2> bool operator()(const std::pair<T1, T2>& left, const std::pair<T1, T2>& right) { return P<T2>()(left.second, right.second); } };
Możesz go używać jako
std::sort(foo.begin(), foo.end(), compare_pair_second<>());
lub
std::sort(foo.begin(), foo.end(), compare_pair_second<std::less>());
źródło
Musiałbyś polegać na niestandardowym select2nd
źródło
Spróbuj zamienić elementy par, aby móc
std::sort()
normalnie używać .źródło