如何根据对的第二个元素对对的向量进行排序?
Posted
技术标签:
【中文标题】如何根据对的第二个元素对对的向量进行排序?【英文标题】:How do I sort a vector of pairs based on the second element of the pair? 【发布时间】:2010-09-21 17:54:23 【问题描述】:如果我有一对向量:
std::vector<std::pair<int, int> > vec;
有没有简单的方法根据对中的第二个元素按递增顺序对列表进行排序?
我知道我可以编写一个小函数对象来完成这项工作,但是有没有办法使用 STL 和 std::less
的现有部分直接完成这项工作?
编辑:我知道我可以编写一个单独的函数或类来传递给第三个参数进行排序。问题是我是否可以用标准的东西来构建它。我真的想要看起来像这样的东西:
std::sort(vec.begin(), vec.end(), std::something_magic<int, int, std::less>());
【问题讨论】:
这里是一个例子:std::sort in a vector of pairs c++ 没有 lamdas 所以你不能完全按照你的意愿去做,你需要创建一个单独的函数/仿函数。这可以是单行的,所以它真的应该没什么大不了的。 C++ 现在有 lambdas 了!哇! 【参考方案1】:编辑:使用 c++14,最好的解决方案非常容易编写,这要归功于现在可以具有 auto
类型参数的 lambda。 这是我目前最喜欢的解决方案
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
【讨论】:
请记住,这与pair<T1,T2>
中的operator<
不同。默认比较器使用 both 第一个和第二个元素(如果第一个元素相等)。这里只使用了第二个。
@Googol:这正是 OP 要求的……他说:"is there and easy way to sort the list in increasing order based on the second element of the pair?"
@evan-teran,是的,我知道。我只是指出如果两个秒元素相等,那么结果可能会令人困惑(例如,如果用于排序)。默认比较器不会遇到此问题,因为它使用第二个元素进行平局。我遇到了这个问题,寻找一个比较器,它使用第二个元素作为比较的主要信息,但我还需要它使用第一个元素来打破平局,所以我想避免其他人错过这一点(正如我在事实上,确实)。【参考方案2】:
你可以像这样使用 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 用于使用 Boost。顺便说一句,使用现代编译器,您可能已经用 std::tr1 替换了 boost,因为这将很快成为标准。 不幸的是,我对 gcc trunk 的 c++1x std::bind 进行了同样的尝试,但它失败了,因为它没有用于绑定的 op 我认为 boost 不是标准的,但它已经足够接近了。 :-) 在此处发布了对此答案的后续问题:***.com/q/4184917/220636【参考方案3】:其实很简单 您使用算法中的排序功能并添加自己的比较功能
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;
【讨论】:
简单而“中肯”。不需要提升或特定的 C++ 版本。 +1 这应该被标记为最佳解决方案。不需要 c++14 来实现。 你能解释一下这个比较是如何工作的吗?我们是否一次将两个元素传递给 myComparision 那么它如何排序?还有,a.second在 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; );
【讨论】:
为什么是if (lhs.second == 0)
?
无特殊含义; lhs.second < rhs.second
可能返回true
或false
,编译器可以清楚地推导出bool
。只是想演示[]() -> Type
案例。
至少对于clang,这种隐式推导可能无法正常工作,我必须添加 ->bool 作为 lambda 返回类型才能使其正常工作。【参考方案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>());
【讨论】:
【参考方案6】:你必须依赖非标准的select2nd
【讨论】:
【参考方案7】:尝试交换对的元素,以便您可以正常使用std::sort()
。
【讨论】:
以上是关于如何根据对的第二个元素对对的向量进行排序?的主要内容,如果未能解决你的问题,请参考以下文章