IEqualityComparer<double> 具有容差;如何实现GetHashCode?

问题描述 投票:0回答:3

我正在实现一个可重用的 DoubleEqualityComparer(具有自定义容差:“epsilon”构造函数参数),以简化 LINQ 与 double 序列的使用。例如:

bool myDoubleFound = doubles.Contains(myDouble, new DoubleEqualityComparer(epsilon: 0.01));

实现 GetHashCode 的正确方法是什么?这是代码:

   public class DoubleEqualityComparer : IEqualityComparer<double>, IEqualityComparer<double?>
    {
        private readonly double epsilon;

        public DoubleEqualityComparer(double epsilon)
        {
            if (epsilon < 0)
            {
                throw new ArgumentException("epsilon can't be negative", "epsilon");
            }

            this.epsilon = epsilon;
        }

        public bool Equals(double x, double y)
        {
            return System.Math.Abs(x - y) < this.epsilon;
        }

        public int GetHashCode(double obj)
        {
            // ?
        }
   }

PS:我总是可以返回相同的值(例如:GetHashCode(double obj){ return 0; })以始终强制调用 Equals(double, double) 方法(我知道性能不是很好),但我记得当比较器与字典一起使用时,此解决方案会出现问题...

.net double hashcode iequalitycomparer epsilon
3个回答
6
投票

我不确定使用

IEqualityComparer<T>
是正确的方法。因为比较的对象不相等。

也许你应该考虑使用一个简单的

Any
子句 + 实用方法:

private static bool DoublesAreNearlyEquals(double d1, double d2, double epsilon = 0.01D)
{
    return System.Math.Abs(d1 - d2) < this.epsilon;
}

private void foo()
{
    var myDoubles = Getdoubles();
    var doubleToSearch = 42D;
    var result = myDoubles.Any(d=>DoublesAreNearlyEquals(d, doubleToSearch));
}

2
投票

我会把

NotSupportedException
扔进
GetHashCode
,这样你就可以鱼与熊掌兼得。 这为您提供了在 LINQ 和其他方法中使用
IEqualityComparer
的便利,但保证了
GetHashCode
的任何使用都会爆炸。 在实践中,您可能会发现使用相等比较器的方式实际上从来不需要调用
GetHashCode
。 您甚至可以将此类称为
NotHashableDoubleEqualityComparer
以非常清楚对调用者的限制。


0
投票

您可以实现只需要

IEqualityComparer<T>
GetHashCode()
,而不是实现需要
IComparer<T>
int Compare(T? x, T? y)

请注意,

SortedDictionary<T>
SortedSet<T>
都有一个接受
IComparer<T>
参数的构造函数重载。

© www.soinside.com 2019 - 2024. All rights reserved.