쌍의 두 번째 요소를 기준으로 쌍으로 구성된 벡터를 어떻게 정렬합니까?


133

쌍으로 구성된 벡터가있는 경우 :

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

쌍의 두 번째 요소를 기반으로 목록을 정렬하는 쉬운 방법이 있습니까?

나는이 일을하는 작은 함수 객체를 작성할 수 있습니다 알고 있지만, 기존의 부품을 사용하는 방법이 STL을 하고 std::less바로 일을 할 수는?

편집 : 정렬 할 세 번째 인수로 전달하는 별도의 함수 또는 클래스를 작성할 수 있음을 이해합니다. 문제는 표준으로 만들 수 있는지 여부입니다. 나는 정말로 다음과 같은 것을 보인다 :

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

다음은 그 예이다 :로 <br> 표준 : 일종의 쌍의 벡터에
LeppyR64

1
c ++에는 라마가 없으므로 원하는 것을 정확하게 수행 할 수 없으므로 별도의 함수 / 펑터를 만들어야합니다. 이것은 하나의 라이너 일 수 있으므로 실제로 큰 문제는 아닙니다.
Evan Teran

1
C ++에는 이제 람다가 있습니다! 우!
David Poole

답변:


212

편집 : c ++ 14를 사용하면 이제 유형 매개 변수를 가질 수있는 람다 덕분에 최상의 솔루션을 작성하는 것이 매우 쉽습니다 auto. 이것은 내가 현재 가장 좋아하는 솔루션입니다

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

커스텀 비교기를 사용하십시오 (선택적 인 세 번째 인수입니다 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());

C ++ 11 컴파일러를 사용하는 경우 람다를 사용하여 동일하게 작성할 수 있습니다.

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

편집 : 질문에 대한 편집 내용에 따라 몇 가지 생각이 있습니다 ... 정말 독창적 이고이 개념을 많이 재사용하려면 템플릿을 만드십시오.

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

그럼 당신도 이것을 할 수 있습니다 :

std::sort(v.begin(), v.end(), sort_pair_second<int, int>());

또는

std::sort(v.begin(), v.end(), sort_pair_second<int, int, std::greater<int> >());

솔직히 말하지만, 이것은 모두 약간 과잉입니다 .3 줄 함수를 작성하고 완료하십시오 :-P


이 다르다는 것을 명심 operator<에서 pair<T1,T2>. 기본 비교기는 첫 번째 요소와 두 번째 요소를 모두 사용 합니다 ( 첫 번째 요소가 같은 경우). 여기서 두 번째 것만 사용됩니다.
Googol

@Googol : 그것은 그가 말한은 ... 영업 이익은 질문이 정확히 무엇이다 : "is there and easy way to sort the list in increasing order based on the second element of the pair?"
에반 테란

@ evan-teran, 예, 알고 있습니다. 두 초 요소가 모두 같으면 결과가 혼란 스러울 수 있음을 나타냅니다 (예를 들어 정렬에 사용되는 경우). 이 문제는 타이 브레이킹에 두 번째 요소를 사용하기 때문에 기본 비교기가 겪지 않습니다. 나는이 질문에 도달하여 비교를 위해 주요 정보로 두 번째 요소를 사용한 비교기를 찾고 있지만, 타이 브레이킹에 첫 번째 요소를 사용해야했기 때문에 다른 사람들이 그 점을 놓치는 것을 피하고 싶습니다. 사실).
Googol

71

다음과 같이 부스트를 사용할 수 있습니다.

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

나는 이것을 똑같이 짧고 간결하게하는 표준 방법을 모르지만, boost::bind모든 것이 헤더로 구성되어 있음을 알 수 있습니다.


1
부스트 사용시 +1 Btw, 최신 컴파일러를 사용하면 부스트를 std :: tr1로 대체 할 수 있습니다. 곧 표준이 될 것입니다.
Andreas Magnusson

불행히도, gcc 트렁크의 c ++ 1x std :: bind와 동일하게 시도했지만 바인드에 대한 op <가 없기 때문에 실패했습니다. 그러나 c ++ 1x가 이것에 대해 말하는 것이 있는지는 모르겠습니다. 아마 그것은 당신에게 그것을 위해 람다를 사용하라고 말합니다 :)
Johannes Schaub-litb

1
나는 부스트가 표준이 아니라고 생각하지만 충분히 가깝습니다. :-)
David Norman

이 답변에 대한 후속 질문을 여기에 게시했습니다. stackoverflow.com/q/4184917/220636
nabulke

34

알고리즘에서 정렬 기능을 사용하고 자신의 비교 기능을 추가하는 것은 매우 간단합니다.

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

이제 두 번째 선택을 기준으로 비교해야하므로 "myComparison"을 다음과 같이 선언하십시오.

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

5
간단하고 "지점". 부스트 또는 특정 C ++ 버전이 필요하지 않습니다. +1
Thomio

1
이것이 최상의 솔루션으로 표시되어야합니다. 그것을 구현하기 위해 c ++ 14가 필요하지 않습니다.
Kartik Chauhan

이 비교가 어떻게 작동하는지 설명해 주시겠습니까? 한 번에 myComparision에 두 가지 요소를 전달하면 어떻게 정렬 할 수 있습니까? 또한 a.second <b.second는 어떤 역할을합니까?
시대 s'q

30

C ++ 0x에서는 람다 함수를 사용할 수 있습니다.

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

이 예제에서 리턴 유형 bool은 내재적으로 추론됩니다.

람다 리턴 유형

람다 함수에 단일 명령문이 있고 이것이 리턴 문인 경우 컴파일러는 리턴 유형을 추론 할 수 있습니다. C ++ 11에서 §5.1.2 / 4 :

...

  • 복합 문이 { return expression ; }lvalue-to-rvalue 변환 (4.1), 배열-포인터 변환 (4.2) 및 함수-포인터 변환 (4.3) 후 리턴 된 표현식의 유형 인 경우;
  • 그렇지 않으면 void.

반환 유형을 명시 적으로 지정하려면 []() -> Type { }다음과 같이 형식을 사용하십시오 .

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
if (lhs.second == 0)?
돼지

특별한 의미는 없습니다. lhs.second < rhs.second반환 true하거나 false컴파일러가 명확하게 추론 할 수 bool있습니다. 그 []() -> Type { }사건 을 보여주고 싶었습니다 .
Andreas Spindler

적어도 clang을 사용하면이 암시 적 공제가 제대로 작동하지 않을 수 있습니다. 올바로 작동하려면 람다 반환 유형으로-> bool을 추가해야했습니다.
MoDJ

5

재사용 할 수있는 것 :

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

당신은 그것을 사용할 수 있습니다

std::sort(foo.begin(), foo.end(), compare_pair_second<>());

또는

std::sort(foo.begin(), foo.end(), compare_pair_second<std::less>());


-1

std::sort()평소처럼 사용할 수 있도록 쌍의 요소를 바꿔보십시오 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.