繁体   English   中英

如何实现IEqualityComparer <PointF> 有了宽容

[英]How to Implement IEqualityComparer<PointF> With Tolerance

这个问题类似于这里的问题

我们都知道PointF是什么,不是吗? 这是数据结构:

public struct PointF
{
  public float X;
  public float Y;
}

如何实现具有容差的IEqualityComparer<PointF> 假设我的Equals代码是这样的

public const float Epsilon = 0.01; //say
public bool Equals(PointF pt1, PointF pt2)
{
   return Math.Abs(pt1.X-pt2.X)<Epsilon && Math.Abs(pt1.Y-pt2.Y)<Epsilon;
}

问题:如何实现正确的GetHashCode以便对于PointF的字典,我将正确访问该元素?

我几天头脑裂开但仍然无法找到满意的解决方案。

您可以将点放在网格中,而不是通过距离定义公差。
如果两个点在同一个单元格中,则它们被认为是相等的并且具有相同的哈希码。

public bool Equals(PointF pt1, PointF pt2)
{
   return GetCell(pt1.X) == GetCell(pt2.X)
       && GetCell(pt1.Y) == GetCell(pt2.Y);
}

public int GetHashCode(PointF pt)
{
   return GetCell(pt.X) ^ GetCell(pt.Y);
}

private static int GetCell(float f)
{
    return (int)(f / 10); // cell size is 10 pixels
}

论文:没有满足您要求的EqualsGetHashCode实现。

证明:考虑以下三点,A,B和C:

插图

根据您的要求,

Equals(A, B) == true              // (i)
Equals(B, C) == true              // (ii)
Equals(A, C) == false             // (iii)
GetHashCode(A) == GetHashCode(B)  // (iv)
GetHashCode(B) == GetHashCode(C)  // (v)
GetHashCode(A) != GetHashCode(C)  // (vi)

但是从(iv)和(v)开始

GetHashCode(A) == GetHashCode(C)

从而

Equals(A, C) == true

这与(iii)和(vi)相矛盾。

由于EqualsGetHashCode不能为相同的参数返回不同的值,因此没有满足您要求的实现。 QED

我不认为这是可能的,因为你可以有一个无限的值序列,它们与序列中的前一个和下一个值相等(在容差范围内)但不是任何其他值,并且GetHashCode需要为所有值返回相同的值。

嗯,基于网格的答案是好的,但有时你需要将关闭点分组,即使它们不在同一个网格单元格中。 我的方法是通过分组来实现这一点:如果它们接近或者有一系列连接它们的关闭点,则两个点在同一组中。 使用适当的IEqualityComparer无法完成此语义,因为它需要在生成组之前事先知道所有项目。 所以我做了一个简单的LINQ风格的运算符GroupByCluster ,基本上实现了这一点。

代码在这里: http//ideone.com/8l0LH 它在我的VS 2010上编译,但无法在Mono上编译,因为HashSet<>无法隐式转换为IEnumerable<> (为什么?)。

该方法是通用的,因此效率不高:它是输入大小的二次方。 对于具体类型,可以使其更有效:例如,对于T = double,我们可以对输入数组进行排序并具有O(n log n)性能。 类似但更复杂的技巧也适用于2D点。


请注意:您的初始命题不可能使用IEqualityComparer实现,因为您的“近似相等”不是可传递的(但IEqualityComparer的相等必须如此)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM