2008-11-11 19 views
104

Jeśli mam wektor par:Jak sortować wektor par na podstawie drugiego elementu pary?

std::vector<std::pair<int, int> > vec; 

istnieje i łatwy sposób sortowania listy rosnące w oparciu o drugi element pary?

wiem, że mogę napisać trochę obiektu funkcji, które będą wykonywać pracę, ale czy jest jakiś sposób, aby wykorzystać istniejące części STL i std::less zrobić bezpośrednio pracę?

EDYCJA: Rozumiem, że mogę napisać oddzielną funkcję lub klasę, aby przejść do trzeciego argumentu do sortowania. Pytanie brzmi, czy mogę zbudować go z standardowych rzeczy. Ja naprawdę coś, co wygląda jak:

std::sort(vec.begin(), vec.end(), std::something_magic<int, int, std::less>()); 
+1

C++ nie ma lamdas, więc nie możesz zrobić dokładnie tego, czego chcesz, musisz utworzyć oddzielną funkcję/funktor. Może to być jeden liniowiec, więc naprawdę nie powinno to być wielkim problemem. –

+0

Oto przykład:
[std :: sort w wektorze par] (http://www.codeguru.com/forum/archive/index.php/t-325645.html) – LeppyR64

Odpowiedz

69

Można użyć impuls tak:

std::sort(a.begin(), a.end(), 
      boost::bind(&std::pair<int, int>::second, _1) < 
      boost::bind(&std::pair<int, int>::second, _2)); 

nie wiem standardowy sposób robienia tego równie krótko i zwięźle, ale można pobrać boost::bind to wszystko składa się z nagłówków.

+1

+1 za korzystanie z funkcji Zwiększ. Btw, z nowoczesnym kompilatorem prawdopodobnie już możesz zastąpić boost ze std :: tr1, ponieważ wkrótce będzie to standard. –

+0

Niestety, próbowałem tego samego z C++ 1x std :: bind gcc trunk, a to nie powiodło się, ponieważ nie ma op

+1

Przypuszczam, że doładowanie nie jest standardem, ale jest wystarczająco blisko. :-) –

170

EDIT: przy użyciu C++ 14, najlepszym rozwiązaniem jest bardzo łatwe do napisania dzięki do lambd, które mogą teraz mieć parametry typu auto. To jest moje obecne rozwiązanie ulubiony

std::sort(v.begin(), v.end(), [](auto &left, auto &right) { 
    return left.second < right.second; 
}); 

Wystarczy użyć niestandardowego komparator (jest to opcja 3-ci argument 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 lambdas:

std::sort(v.begin(), v.end(), [](const std::pair<int,int> &left, const std::pair<int,int> &right) { 
    return left.second < right.second; 
}); 

EDIT: w odpowiedzi na Twoich zmian na swoje pytanie, oto kilka myśli ... jeśli naprawdę chce być kreatywny i móc ponownie wykorzystać tą koncepcją dużo, po prostu zrobić 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); 
    } 
}; 

następnie można to zrobić też:

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> >()); 

Choć szczerze mówiąc, to wszystko jest trochę przesada, wystarczy napisać funkcję linia 3 i być z nim zrobić :-P

+59

+1 do użytku standardowego STL, a nie zwiększenia! – ragebiswas

+0

Należy pamiętać, że różni się to od 'operatora <' w 'pair '. Domyślny komparator używa * obu * pierwszego i drugiego elementu (w przypadku, gdy pierwsze są równe). Tutaj używany jest tylko drugi. – Googol

+0

@Googol: Właśnie o to prosił OP ... Powiedział: '" czy istnieje łatwy sposób sortowania listy w porządku rosnącym w oparciu o drugi element pary? "' –

5

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żna 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>()); 
29

z C++ 0x możemy wykorzystać funkcje 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 domyślnie wydedukowany.

Lambda rodzaje powrotne

Gdy funkcja lambda ma pojedynczą instrukcję, a to jest zwrot oświadczenie, kompilator może wywnioskować typ zwracany. Od C++ 11, §5.1.2/4:

...

  • Jeśli związek-deklaracja ma postać { return expression ; } typ zwracanej wypowiedzi po lwartość do RValue konwersja (4.1), konwersja tablicy do wskaźnika (4.2) i konwersja funkcji do wskaźnika (4.3);
  • inaczej, void.

Aby jednoznacznie określić typ zwracanej skorzystać z formularza []() -> Type { }, jak w:

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; }); 
+1

Dlaczego 'if (lhs.second == 0)'? –

+0

Brak konkretnego znaczenia; 'lhs.second Type {}". –

19

jest dość prosty użyć funkcji sortowania z algorytmu i dodać własne porównanie funkcji

vector< pair<int,int > > v; 
sort(v.begin(),v.end(),myComparison); 

Teraz musisz dokonać porównania na podstawie drugiej selekcji , tak aby zadeklarować "myComp" Arison”jako

bool myComparison(const pair<int,int> &a,const pair<int,int> &b) 
{ 
     return a.second<b.second; 
} 
+4

Proste i "do punktu". Nie wymaga wzmocnienia lub określonej wersji C++. +1 – Thomio

+0

To powinno być oznaczone jako najlepsze rozwiązanie. Nie wymaga C++ 14 do jego implementacji. –

-1

Spróbuj zamiana elementów par, dzięki czemu można używać std::sort() jako normalne.

Powiązane problemy