C# 元组的IEqualityComparer
我使用2、3和4位小数的元组,例如:C# 元组的IEqualityComparer,c#,C#,我使用2、3和4位小数的元组,例如: (Decimal? x, Decimal? y, Decimal? z) p1 = (1.25m, 2.12m, 3.14m); (Decimal? x, Decimal? y, Decimal? z) p2 = (1.24m, 2.11m, 3.16m); 我需要通过比较每个Decimal?值来检查p1是否等于p2 为了比较两个十进制值,我有以下IEqualityComparer: public class DecimalToleranceEqua
(Decimal? x, Decimal? y, Decimal? z) p1 = (1.25m, 2.12m, 3.14m);
(Decimal? x, Decimal? y, Decimal? z) p2 = (1.24m, 2.11m, 3.16m);
我需要通过比较每个Decimal?
值来检查p1
是否等于p2
为了比较两个十进制值,我有以下IEqualityComparer
:
public class DecimalToleranceEqualityComparer : IEqualityComparer<Decimal?> {
private readonly Decimal _tolerance;
public DecimalToleranceEqualityComparer(Decimal tolerance) {
_tolerance = tolerance;
}
public Boolean Equals(Decimal? x, Decimal? y) {
if (!x.HasValue && !y.HasValue)
return true;
else if (!x.HasValue || !y.HasValue)
return false;
else
return Math.Abs(x.Value - y.Value) <= _tolerance;
}
public Int32 GetHashCode(Decimal? obj) {
return obj.GetHashCode();
}
}
公共类DecimalToleranceQualityComparer:IEqualityComparer{
专用只读十进制_公差;
公共十进制公差质量比较器(十进制公差){
_公差=公差;
}
公共布尔等于(十进制?x,十进制?y){
如果(!x.HasValue&&!y.HasValue)
返回true;
else如果(!x.HasValue | |!y.HasValue)
返回false;
其他的
return Math.Abs(x.Value-y.Value)我发现您的十进制比较器存在两个主要问题,这两个问题都源于“容差”的容差:
GetHashCode
与'Equals'不兼容-两个“equal”的小数可能具有不同的哈希代码
Equals
是不可传递的。假设您的公差为1。那么1.2和2.0将是“相等”,2.0和2.9将是“相等”,但1.2和2.9将不是“相等”。不可传递的相等可能有问题
如果忽略容差,则可以对没有这些问题的小数(和元组)使用内置的相等
但是,为了好玩,一个实现可以是使用您拥有的比较器(或默认的Double?
comparer),并比较p1.Item1和p2.Item1,等等:
public class DecimalTupleEqualityComparer : IEqualityComparer<(Decimal?,Decimal?,Decimal?)> {
private readonly Decimal _tolerance;
private readonly IEqualityComparer<Decimal?> _comparer;
public DecimalTupleEqualityComparer(Decimal tolerance) : this(tolerance, null) {}
public DecimalTupleEqualityComparer(Decimal tolerance, IEqualityComparer<Decimal?> comparer) {
if (comparer==null)
{
_comparer = EqualityComparer<Decimal?>.Default;
}
else
{
_comparer = comparer;
}
}
public Boolean Equals((Decimal?,Decimal?,Decimal?) x, (Decimal?,Decimal?,Decimal?) y) {
foreach (var (v1,v2) in new[] {(x.Item1, y.Item1), (x.Item2, y.Item2),(x.Item3, y.Item3)})
if (!_comparer.Equals(v1,v2))
return false;
return true;
}
public Int32 GetHashCode((Decimal?,Decimal?,Decimal?) obj) {
return obj.Item1.GetHashCode() ^ obj.Item2.GetHashCode() ^ obj.Item2.GetHashCode();
}
}
公共类DecimalTupleEqualityComparer:IEqualityComparer{
专用只读十进制_公差;
专用只读IEqualityComparer\u comparer;
公共DecimalTupleEqualityComparer(十进制容差):此(容差,null){}
公共十进制整数等式比较器(十进制公差、IEqualityComparer比较器){
if(比较器==null)
{
_comparer=EqualityComparer.Default;
}
其他的
{
_比较器=比较器;
}
}
公共布尔值等于((十进制?,十进制?,十进制?)x,(十进制?,十进制?,十进制?)y){
foreach(var(v1,v2)在新[]{(x.Item1,y.Item1),(x.Item2,y.Item2),(x.Item3,y.Item3)}
如果(!\u比较器等于(v1,v2))
返回false;
返回true;
}
公共Int32 GetHashCode((十进制?,十进制?,十进制?)对象){
返回obj.Item1.GetHashCode()^obj.Item2.GetHashCode()^obj.Item2.GetHashCode();
}
}
你的意思是(十进制x,十进制y,十进制z)p2=(1.24m,2.11m,3.16m);
?(你的问题中有p1
)是的,刚刚更正。我需要比较两个元组<代码> P1<代码>和<代码> P2<代码>你有比较器。你只需要一个比较器。要么创建一个扩展方法,要么定义一个委托或者创建一个静态助手。你将如何解决你指出的2个问题?我需要使用一个宽容,因为我在我考虑的单元测试中使用它。2.21和2.22足够相等…我不知道有什么方法可以定义一个具有可传递公差的相等比较器。如果你只是在单元测试中使用它们,你可以在单元测试中进行比较,而不是定义一个相等比较器。也就是说,如果你将比较器用作查找键或需要及物性的东西。如果你在使用它时没有产生问题,那么它可能不需要被修复。我同意@DStanley。假设你能神奇地修复#2,你会如何修复#1?什么“规则”你能想出一个办法让两个哈希代码在两个小数点上相同,并且在公差范围内相等吗?你必须以某种方式对哈希代码进行规范化。看起来哈希代码会退化到最坏的情况:所有哈希代码都相等!这完全违背了哈希的目的。也许我能看到的唯一解决这个问题的方法是forc将所有的小数点精确到相同的精度,并摆脱容忍的概念;在这种情况下,您可以使其一致且具有确定性。您可以将每个值舍入到一定数量的小数点(也可以用于哈希代码),但你会遇到一些奇怪的情况,比如1.51和2.49相等,但2.49和2.51不相等。是的,这就是我通过“强制到相同精度”所想的。我想我可以在这里使用“圆形:)但是,它回到了你提到的同一个问题。