Bir çift vektörünü çiftin ikinci elemanına göre nasıl sıralayabilirim?


133

Bir çift vektörüm varsa:

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

Çiftin ikinci unsuruna göre listeyi artan sırada sıralamanın kolay bir yolu var mı?

Ben işi yapacak biraz fonksiyon nesnesi yazabilirsiniz biliyorum ama mevcut parçalarını kullanmak için bir yol yoktur STL ve std::lessdoğrudan işi yapmak için?

DÜZENLEME: Sıralamak için üçüncü bağımsız değişkene geçmek için ayrı bir işlev veya sınıf yazabileceğimi anlıyorum. Soru, onu standart malzemelerden inşa edip edemeyeceğim. Gerçekten şöyle görünen bir şey isterim:

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

İşte bir örnek: <br> std :: sort bir çift vektörde
LeppyR64

1
c ++ lamdalarına sahip değildir, bu yüzden tam olarak istediğinizi yapamazsınız, ayrı bir işlev / functor oluşturmanız gerekir. Bu tek astarlı olabilir, bu yüzden gerçekten önemli bir şey olmamalı.
Evan Teran

1
C ++ 'da artık lambdalar var! Woo!
David Poole

Yanıtlar:


212

DÜZENLEME : c ++ 14 kullanarak, artık tür parametrelere sahip olabilen lambdalar sayesinde en iyi çözümü yazmak çok kolaydır auto. Bu benim şu anki favori çözümüm

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

Sadece özel bir karşılaştırıcı kullanın (isteğe bağlı 3. bağımsız değişken 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());

Bir C ++ 11 derleyicisi kullanıyorsanız, aynısını lambdas kullanarak yazabilirsiniz:

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

DÜZENLEME : Sorunuzdaki düzenlemelerinize yanıt olarak, işte bazı düşünceler ... Gerçekten yaratıcı olmak ve bu kavramı çok fazla yeniden kullanmak istiyorsanız, bir şablon hazırlayın:

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

o zaman bunu da yapabilirsiniz:

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

ya da

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

Dürüst olmak gerekirse, bunların hepsi biraz abartılı, sadece 3 satır işlevini yazın ve onunla bitirin :-P


Bu farklı olduğunu unutmayın operator<içinde pair<T1,T2>. Varsayılan karşılaştırıcı hem birinci hem de ikinci öğeyi kullanır (ilk öğelerin eşit olması durumunda). Burada sadece ikincisi kullanılıyor.
Googol

@Googol: OP'nin istediği de tam olarak buydu ... Dedi ki: "is there and easy way to sort the list in increasing order based on the second element of the pair?"
Evan Teran

@ evan-teran, evet, biliyorum. Sadece her iki saniye öğesi de eşitse, sonucun kafa karıştırıcı olabileceğini belirtiyordum (örneğin sıralama için kullanılıyorsa). Bu sorun, varsayılan karşılaştırıcı tarafından yaşanmaz, çünkü bağlantı kırmak için ikinci öğeyi kullanır. Bu soruya, ikinci öğeyi karşılaştırma için ana bilgi olarak kullanan bir karşılaştırıcı ararken ulaştım, ancak aynı zamanda ilkini bağ kırmak için kullanmasına da ihtiyacım vardı, bu nedenle başkalarının bu noktayı kaçırmasını önlemek istiyorum ( aslında yaptım).
Googol

71

Boost'u şu şekilde kullanabilirsiniz:

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

Bunu eşit derecede kısa ve özlü yapmanın standart bir yolunu bilmiyorum, ancak boost::bindhepsini başlıklardan oluştuğunu anlayabilirsiniz .


1
Boost kullanmak için +1. Btw, modern bir derleyici ile boost'u zaten std :: tr1 ile değiştirebilirdiniz, çünkü bu yakında standartta olacak.
Andreas Magnusson

ne yazık ki, aynı şeyi gcc trunk's c ++ 1x std :: bind ile denedim ve başarısız oldu çünkü op <for bind. ancak c ++ 1x'in bu konuda ne söylediğini bilmiyoruz. muhtemelen bunun için lambda kullanmanızı söyler :)
Johannes Schaub - litb

1
Sanırım güçlendirme standart değil ama yeterince yakın. :-)
David Norman

Bu yanıtı burada takip eden bir soru
yayınladı

34

Oldukça basit, algoritmadan sıralama işlevini kullanın ve kendi karşılaştırma işlevinizi ekleyin

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

Şimdi karşılaştırmayı ikinci seçime göre yapmanız gerekiyor, bu nedenle "myComparison" olarak ilan edin

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

5
Basit ve "isabetli". Takviye veya belirli bir C ++ sürümüne ihtiyaç duymaz. +1
Thomio

1
Bu, en iyi çözüm olarak işaretlenmelidir. Uygulamak için c ++ 14'e ihtiyaç duymaz.
Kartik Chauhan

Bu karşılaştırmanın nasıl çalıştığını bana açıklayabilir misin? Bir seferde myComparision'a iki öğe aktarıyor muyuz, o zaman nasıl sıralayabiliriz? Ayrıca, a.second <b.second hangi rolü oynar?
dönem s'q

30

C ++ 0x ile lambda işlevlerini kullanabiliriz:

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

Bu örnekte dönüş türü booldolaylı olarak çıkarılmıştır.

Lambda dönüş türleri

Bir lambda işlevi tek bir ifadeye sahip olduğunda ve bu bir dönüş ifadesi olduğunda, derleyici dönüş türünü çıkarabilir. C ++ 11, §5.1.2 / 4'ten:

...

  • Bileşik-deyimi, { return expression ; }ldeğerden rvalue dönüşümünden (4.1), diziden işaretçiye dönüşümden (4.2) ve fonksiyondan işaretçiye dönüşümden (4.3) sonra döndürülen ifadenin türü biçiminde ise;
  • aksi takdirde void,.

İade türünü açıkça belirtmek için aşağıdaki []() -> Type { }gibi formu kullanın :

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
Neden if (lhs.second == 0)?
the swine

Belirli bir anlamı yok; lhs.second < rhs.seconddöndürebilir trueveya falseve derleyici açıkça çıkarabiliriz bool. Sadece []() -> Type { }davayı göstermek istedim .
Andreas Spindler

En azından clang ile, bu örtük kesinti düzgün çalışmayabilir, düzgün çalışmasını sağlamak için lambda dönüş türü olarak -> bool eklemek zorunda kaldım.
MoDJ

5

Yeniden kullanılabilir bir şey için:

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

Olarak kullanabilirsiniz

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

veya

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


-1

std::sort()Normal olarak kullanabilmek için çiftlerin öğelerini değiştirmeyi deneyin .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.