كيف أقوم بفرز متجه الأزواج بناءً على العنصر الثاني من الزوج؟

StackOverflow https://stackoverflow.com/questions/279854

  •  07-07-2019
  •  | 
  •  

سؤال

إذا كان لدي ناقل للأزواج:

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

هل هناك طريقة سهلة لفرز القائمة بترتيب تصاعدي بناءً على العنصر الثاني من الزوج؟

أعلم أنه يمكنني كتابة كائن وظيفي صغير يقوم بالعمل، ولكن هل هناك طريقة لاستخدام الأجزاء الموجودة من المحكمة الخاصة بلبنان و std::less للقيام بهذا العمل مباشرة؟

يحرر:أدرك أنه يمكنني كتابة دالة أو فئة منفصلة لتمريرها إلى الوسيطة الثالثة للفرز.والسؤال هو ما إذا كان بإمكاني بنائه من الأشياء القياسية أم لا.أود حقًا أن يبدو الأمر كما يلي:

std::sort(vec.begin(), vec.end(), std::something_magic<int, int, std::less>());
هل كانت مفيدة؟

المحلول

يحرر:باستخدام c++ 14، من السهل جدًا كتابة الحل الأفضل بفضل lambdas التي يمكن أن تحتوي الآن على معلمات من النوع 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، فيمكنك كتابة نفس الشيء باستخدام lambdas:

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

نصائح أخرى

ويمكنك استخدام دفعة من هذا القبيل:

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

وأنا لا أعرف وسيلة معيارية للقيام بذلك باختصار على قدم المساواة وموجزة، ولكن يمكنك انتزاع boost::bind انها تتكون كل الرؤوس.

مع 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 ; } نوع التعبير الذي تم إرجاعه بعد تحويل القيمة إلى قيمة r (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; } );

وه بسيطة جميلة يمكنك استخدام الدالة نوع من خوارزمية وإضافة وظيفة مقارنة الخاصة بك

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

لشيء قابلة لإعادة الاستخدام:

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

وأنت تريد أن تعتمد على غير القياسية select2nd

وحاول مبادلة عناصر أزواج بحيث يمكنك استخدام std::sort() كالمعتاد.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top