避免 HashSet<double> 中的重复值略有不同

abe*_*nci 9 .net c# collections visual-studio

我正在尝试跳过以下值列表的重复项。我试图实现的结果是-112.94487230674, -49.47838592529, -89.9999574979198,我正在使用HashSet类。我已经实现了下面的IEqualityComparer但它不起作用。

我究竟做错了什么?

    class HeightEqualityComparer : IEqualityComparer<double>
    {
        public bool Equals(double a, double b)
        {
            return a - b < 1e-3;
        }

        public int GetHashCode(double value)
        {
            return value.GetHashCode();
        }
    }
Run Code Online (Sandbox Code Playgroud)

以下是值列表:

    [0] -112.94487230674    double
    [1] -112.94487230674001 double
    [2] -49.478385925290006 double
    [3] -49.47838592529     double
    [4] -49.478385925289992 double
    [5] -89.9999574979198   double
    [6] -89.99995749791978  double
    [7] -49.478385925289984 double
    [8] -89.999957497919809 double
    [9] -49.478385925290013 double
Run Code Online (Sandbox Code Playgroud)

Dmi*_*nko 6

那么,目前的实施 Equals

   return a - b < 1e-3;
Run Code Online (Sandbox Code Playgroud)

不正确的Equals必须是

  1. Equals(a, a) == true;
  2. 对称Equals(a, b) == Equals(b, a);
  3. 传递 Equals(a, b) && Equals(b, c)导致Equals(a, c);

条件23在当前实施中不成立。在Math.Abs;的帮助下很容易修复第二个条件;第三个是真正的困难:对于任意正数tolerance1e-3在你的情况下),我们有

   a == a + tolerance == a + 2 * tolerance == ... == a + n * tolerance  
Run Code Online (Sandbox Code Playgroud)

意思是

   a == a + n * tolerance
Run Code Online (Sandbox Code Playgroud)

对于任意大 n; 因此a == b对于所有ab(所有数字都相等)。

作为部分(但有效)的解决方案,您可以尝试四舍五入这些值:

   class HeightEqualityComparer : IEqualityComparer<double>
   {
       public bool Equals(double a, double b)
       {
           return Math.Round(a, 3) == Math.Round(b, 3);
       }

       public int GetHashCode(double value)
       {
           return Math.Round(value, 3).GetHashCode();
       }
   } 
Run Code Online (Sandbox Code Playgroud)

注意,我们必须改变 GetHashCode