如何根据对的第二个元素对向量进行排序?


133

如果我有一对向量:

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

有没有一种简单的方法可以基于该对的第二个元素按升序对列表进行排序?

我知道我可以编写一个可以完成工作的小函数对象,但是有没有办法使用STL的现有部分并std::less直接进行工作呢?

编辑:我了解我可以编写一个单独的函数或类以传递给第三个参数进行排序。问题是我是否可以用标准的东西建造它。我真的看起来像这样:

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


1
c ++没有lamda,因此您无法完全执行所需的操作,因此需要创建一个单独的函数/函数。这可以是一个单行,所以它实际上应该没什么大不了的。
伊万·特兰

1
C ++现在有lambdas!!
大卫·普尔

Answers:


212

编辑:使用c ++ 14,最好的解决方案非常容易编写,这要归功于lambdas现在可以具有type参数了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编译器,则可以使用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


请记住,这是从不同operator<pair<T1,T2>。默认比较器使用两个第一和第二元件(在第一情况下的有相等)。这里仅使用第二个。
Googol 2014年

@Googol:这正是OP要求的...他说: "is there and easy way to sort the list in increasing order based on the second element of the pair?"
Evan Teran 2014年

@ evan-teran,是的,我知道。我只是指出,如果两个秒元素都相等,那么结果可能会令人困惑(例如,如果用于排序)。默认比较器不会遇到此问题,因为它将第二个元素用于平局决胜。我遇到了这个问题,正在寻找一个比较器,该比较器使用第二个元素作为比较的主要信息,但是我也需要它使用第一个元素进行平局,所以我想避免其他人错过这一点(因为我事实上)。
Googol 2014年

71

您可以这样使用boost:

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用于使用Boost。顺便说一句,使用现代编译器,您可能已经用std :: tr1替换了boost,因为它将很快成为标准。
Andreas Magnusson,

不幸的是,我在gcc trunk的c ++ 1x std :: bind上尝试了相同的操作,但失败了,因为它没有用于绑定的op <。但是dunno是否c ++ 1x对此表示了什么。可能它告诉您使用lambda :)
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
简单而“指向重点”。不需要boost或特定的C ++版本。+1
Thomio '16

1
这应该被标记为最佳解决方案。不需要c ++ 14来实现它。
Kartik Chauhan,

您能向我解释一下这种比较的原理吗?我们是否一次将两个元素传递给myComparision,然后如何排序?另外,a.second <b.second扮演什么角色?
时代

30

使用C ++ 0x,我们可以使用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; } );

在此示例中,返回类型bool是隐式推导的。

Lambda返回类型

当lambda函数具有单个语句,并且这是一个返回语句时,编译器可以推断出返回类型。从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 { }
Andreas Spindler

至少对于clang来说,这种隐式推论可能无法正常工作,我必须添加-> bool作为lambda返回类型才能使其正常工作。
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>());


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.