C++ 如何比较结构
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11703853/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
how to compare structs
提问by NaomiJO
I am having difficulties to set up the comparison correctly. Here is an example of my problem, where my code wrongly assumes {1,2}={2,1}: http://ideone.com/i7huL
我很难正确设置比较。这是我的问题的一个例子,我的代码错误地假设 {1,2}={2,1}:http: //ideone.com/i7huL
#include <iostream>
#include <map>
using namespace std;
struct myStruct {
int a;
int b;
bool operator<(const myStruct& rhs) const {
return rhs.a < this->a && rhs.b < this->b;
}
};
int main() {
std::map <myStruct, int> mymap ;
myStruct m1={1,2};
myStruct m2={2,1};
mymap.insert(make_pair(m1,3));
std::map<myStruct, int>::iterator it1 = mymap.find(m1);
std::map<myStruct, int>::iterator it2 = mymap.find(m2);
cout << it1->second << it2->second;
// here it1->second=it2->second=3, although I would have expected it2 to be equal to map.end().
}
I could use || instead of &&, but I'm not sure this is the correct way either. I just want to have operator< implemented in such a way that I am able to find objects in my map, without making any errors, as is the case in the code I linked to.
我可以使用 || 而不是&&,但我不确定这是否也是正确的方法。我只想让 operator< 以这样一种方式实现,即我能够在我的地图中找到对象,而不会出现任何错误,就像我链接到的代码中的情况一样。
Thanks.
谢谢。
回答by Hans Passant
Yes, this operator implementation doesn't make much sense. I'd recommend:
是的,这个操作符实现没有多大意义。我建议:
bool operator<(const myStruct& rhs) const {
return rhs.a < this->a || (rhs.a == this->a && rhs.b < this->b);
}
回答by juanchopanza
bool operator<(const myStruct& rhs) const {
if (a < rhs.a) return true;
if (a == rhs.a) return b < rhs.b;
return false;
}
If you are looking for a generalization to many data members, there is a great example using C++11 std::tie:
如果您正在寻找对许多数据成员的概括,有一个使用 C++11 std::tie的很好的例子:
struct S {
int n;
std::string s;
float d;
bool operator<(const S& rhs) const {
return std::tie(n, s, d) < std::tie(rhs.n, rhs.s, rhs.d);
}
};
回答by Benjamin Lindley
The problem is that your operator does not define a strict weak ordering. Think through your how your example of {1,2}
and {2,1}
would go down in your operator. Assume X = {1,2}
, and Y = {2,1}
.
问题是您的运营商没有定义严格的弱排序。想通过你如何你的例子{1,2}
并{2,1}
会往下走你的运营商。假设X = {1,2}
, 和Y = {2,1}
。
Is X < Y? Is 1 < 2 AND2 < 1? No, therefore X is not less than Y.
X < Y 吗?是 1 < 2 AND2 < 1?不,因此 X 不小于 Y。
Is Y < X? Is 2 < 1 AND1 < 2? No, therefore Y is not less than X.
Y < X 吗?是 2 < 1 AND1 < 2 吗?不,因此 Y 不小于 X。
So, if X is not less than Y, and Y is not less than X, what's left? They're equal.
那么,如果 X 不小于 Y,并且 Y 不小于 X,还剩下什么?他们是平等的。
You need to pick one of the members of your struct, either a
or b
to be the primary comparison. If the primary comparison results in equality, only thendo you check the secondary comparison. Just like when you alphabetizesomething. First you check the first letter, and only if they are equal do you go on to the next. Hans Passant has provided an example of this.
你需要选择你的结构的成员之一,无论是a
或者b
是主要的比较。如果主要比较结果相等,那么您才检查次要比较。就像你按字母顺序排列某些东西一样。首先你检查第一个字母,只有当它们相等时你才能继续下一个。Hans Passant 提供了一个例子。
Here's a more serious problem example for your operator. The one I gave above is not necessarilybad, because maybe you want{1,2}
to be considered equal to {2,1}
. The fundamental problem crops with a set of values like this: consider X = {1,1}, Y = {1,2}, Z = {2,2}
这是您的操作员的一个更严重的问题示例。我上面给出的不一定是坏的,因为也许你想{1,2}
被认为等于{2,1}
. 基本问题是用一组这样的值产生的:考虑X = {1,1}, Y = {1,2}, Z = {2,2}
With your operator, X is definitively less than Z, because 1 is less than 2. But X comes out equal to Y, and Y comes out equal to Z. In order to adhere to strict weak ordering, if X = Y, and Y = Z, then X should equal Z. But here that is not the case.
对于您的运算符,X 肯定小于 Z,因为 1 小于 2。但 X 等于 Y,Y 等于 Z。为了遵守严格的弱排序,如果 X = Y,并且 Y = Z,那么 X 应该等于 Z。但这里不是这样。
回答by jahhaj
You asked about generalising to four int members, here's how I would structure such code for maximum clarity.
您询问了概括为四个 int 成员的问题,以下是我将如何构建此类代码以实现最大清晰度。
bool operator<(const myStruct& rhs) const
{
if (a < rhs.a)
return true;
if (a > rhs.a)
return false;
if (b < rhs.b)
return true;
if (b > rhs.b)
return false;
if (c < rhs.c)
return true;
if (c > rhs.c)
return false;
if (d < rhs.d)
return true;
if (d > rhs.d)
return false;
return false;
}
You can easily extend such code for as many data members as you wish.
您可以轻松地为任意数量的数据成员扩展此类代码。
回答by Puppy
The simplest solution uses std::tie
to compare the tuples.
最简单的解决方案用于std::tie
比较元组。
return std::tie(rhs.a, rhs.b) < std::tie(a, b);
This generalizes very quickly and simply to more data members.
这非常快速且简单地推广到更多数据成员。
回答by Brangdon
I prefer to write this by comparing elements for equality until two are found that are different:
我更喜欢通过比较元素的相等性来写这个,直到发现两个不同的元素:
bool operator<(const myStruct& rhs) const {
if (a != rhs.a)
return a < rhs.a;
if (b != rhs.b)
return b < rhs.b;
return false; // this and rhs are equal.
}
I find this clearer and more extensible than writing a single expression with a mix of || and && (as per @HansPassant), and more compact than @jahhaj's approach of having each passing test lead to a return true;
or return false;
. Performance is about the same, unless you know something about the distribution of values. There is an argument for avoiding operator==()
and just using operator<()
, but that only applies if you are trying to write maximally generic template code.
我发现这比用 || 混合编写单个表达式更清晰、更可扩展 和&&(根据@HansPassant),并且比@jahhaj 让每个通过的测试都指向 areturn true;
或的方法更紧凑return false;
。性能大致相同,除非您对值的分布有所了解。有一个避免operator==()
和只使用的论据operator<()
,但这仅适用于您尝试编写最大程度通用的模板代码的情况。
回答by PermanentGuest
Problem is that you need to know what your structure represents. Otherwise defining a < operator would just become arbitrary. Others won't be able to give you a fitting answer. Take an example where when your structure represents a cartisian coordinate of a point in 2D. In this case you could define a meaningful ordering operator such as the distance from the origin for the structure.
问题是你需要知道你的结构代表什么。否则定义 < 运算符将变得随意。其他人无法给你一个合适的答案。举个例子,当你的结构表示一个点在 2D 中的笛卡尔坐标时。在这种情况下,您可以定义一个有意义的排序运算符,例如距结构原点的距离。
i.e, distance d1 = this->a*this->a + this->b*this->b distance d2 = rhs.a*rhs.a + rhs.b*rhs.b if(d1 < d2) return true; else return false;
即,距离 d1 = this->a*this->a + this->b*this->b 距离 d2 = rhs.a*rhs.a + rhs.b*rhs.b if(d1 < d2) return true ; 否则返回假;