मैं जोड़े के दूसरे तत्व के आधार पर जोड़े के वेक्टर को कैसे सॉर्ट करता हूं?


133

यदि मेरे पास जोड़े का वेक्टर है:

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

क्या जोड़ी के दूसरे तत्व के आधार पर बढ़ते क्रम में सूची को सॉर्ट करने का आसान और आसान तरीका है?

मुझे पता है कि मैं एक छोटी सी फ़ंक्शन ऑब्जेक्ट लिख सकता हूं जो काम करेगा, लेकिन क्या एसटीएल के मौजूदा हिस्सों का उपयोग करने और std::lessसीधे काम करने का एक तरीका है ?

संपादित करें: मैं समझता हूं कि मैं तीसरे तर्क को हल करने के लिए एक अलग फ़ंक्शन या वर्ग लिख सकता हूं। सवाल यह है कि मैं इसे मानक सामान से बाहर बना सकता हूं या नहीं। मुझे वास्तव में कुछ ऐसा लगेगा जो दिखता है:

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


1
c ++ में lamdas नहीं है, इसलिए आप वास्तव में वही नहीं कर सकते जो आप चाहते हैं, आपको एक अलग फ़ंक्शन / फ़ंक्टर बनाने की आवश्यकता होगी। यह वन-लाइनर हो सकता है इसलिए यह वास्तव में बड़ी बात नहीं होनी चाहिए।
इवान टेरान

1
C ++ में अब लैम्ब्डा है! वू!
डेविड पूले

जवाबों:


212

EDIT : c ++ 14 का उपयोग करते हुए, सबसे अच्छा समाधान लैम्ब्डा के लिए धन्यवाद लिखना बहुत आसान है जो अब प्रकार के पैरामीटर हो सकते हैं autoयह मेरा वर्तमान पसंदीदा समाधान है

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

बस एक कस्टम तुलनित्र का उपयोग करें (यह एक वैकल्पिक 3 तर्क है 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: ठीक यही बात ओपी ने पूछी ... उसने कहा: "is there and easy way to sort the list in increasing order based on the second element of the pair?"
इवान टेरान

@ इवान-तरण, हां, मुझे पता है। मैं केवल यह संकेत दे रहा था कि यदि दोनों सेकंड तत्व समान हैं, तो परिणाम भ्रामक हो सकता है (यदि छँटाई के लिए उपयोग किया जाता है, उदाहरण के लिए)। यह समस्या डिफ़ॉल्ट तुलनित्र द्वारा सामना नहीं की गई है क्योंकि यह टाई-ब्रेकिंग के लिए दूसरे तत्व का उपयोग करती है। मैं इस प्रश्न पर एक तुलनित्र की तलाश में पहुंचा, जिसने तुलना करने के लिए मुख्य तत्व के रूप में दूसरे तत्व का उपयोग किया, लेकिन मुझे यह भी आवश्यकता थी कि यह टाई-ब्रेकिंग के लिए पहले एक का उपयोग करे, इसलिए मैं दूसरों से बचने के लिए उस बिंदु को याद करना चाहूंगा (जैसा कि, मैं तथ्य, किया)।
गोगोल

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 के साथ बढ़ावा दे सकते हैं क्योंकि यह जल्द ही मानक में होगा।
एंड्रियास मैग्यूसन

दुर्भाग्य से, मैंने gcc ट्रंक के c ++ 1x std :: bind के साथ ऐसा ही प्रयास किया, और यह विफल रहा क्योंकि इसमें op <bind के लिए नहीं है। dunno हालांकि क्या c ++ 1x इस बारे में कहता है। शायद यह आपको लगता है कि :) के लिए लैम्ब्डा उपयोग करने के लिए कहता है
litb - Johannes Schaub

1
मुझे लगता है कि बढ़ावा मानक नहीं है, लेकिन यह काफी करीब है। :-)
डेविड नॉर्मन

इस उत्तर के लिए एक अनुवर्ती प्रश्न पोस्ट करें: 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
थोमाओ

1
यह सबसे अच्छा समाधान के रूप में चिह्नित किया जाना चाहिए। इसे लागू करने के लिए c ++ 14 की आवश्यकता नहीं है।
कार्तिक चौहान

क्या आप मुझे समझा सकते हैं कि यह तुलना कैसे काम करती है? क्या हम एक समय में 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 ; } का है, जो लैवल्यू-टू-रिवेल्यू रूपांतरण (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 { }मामले को प्रदर्शित करना चाहता था ।
एंड्रियास स्पिंडलर

कम से कम क्लैंग के साथ, यह निहित कटौती ठीक से काम नहीं कर सकती है, मुझे इसे जोड़ना होगा - लैंबडा रिटर्न टाइप के रूप में इसे ठीक से काम करने के लिए।
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()सामान्य रूप से उपयोग कर सकें ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.