如何实现的IEqualityComparer <的PointF>用宽容
-
20-09-2019 - |
题
此问题类似于此处 之一。
我们都知道的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
}
论文:有没有Equals
和GetHashCode
能满足你需求的实现
<强>证明:强>考虑以下三点,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)
但是,从(ⅳ)和(ⅴ)如下
GetHashCode(A) == GetHashCode(C)
和由此
Equals(A, C) == true
这违背(iii)和(VI)。
由于Equals
和GetHashCode
不能为相同的参数返回不同的值,也没有能满足你需求的实现。
的 q.e.d。强>
其他提示
我不认为这是可能的,因为你可以有相等(公差范围内)值序列中的前一个和下一个值的无限序列,但没有任何其他价值和GetHashCode
需要返回相同的值所有这些。
那么,基于网格的答案是好的,但有时你需要组反正收盘点,即使他们不在同一个网格单元。我的做法是用分组来实现这一点:两点为同组,如果他们要么是关闭或存在的接近点的连接它们的序列。这种语义不能用正确的IEqualityComparer
来完成,因为它需要制作组之前事先知道所有项目。所以我做了一个简单的LINQ风格的操作GroupByCluster
,基本上实现了这一点。
的代码是在这里: http://ideone.com/8l0LH 。它编译我的VS 2010,但未能在单编译,因为HashSet<>
不能被隐式转换为IEnumerable<>
(为什么?)。
的方法是一般性的,因此不是非常有效的:它的上输入大小二次。对于具体类型它可以制成更有效的:例如,对于T =双我们可以只排序所述输入阵列和已O(n log n)
性能。类似的,虽然更复杂的特技适用于2D点为好。
请注意一旁:初始命题是不可能的IEqualityComparer
实现,因为你的“近似相等”是不是传递(但在IEqualityComparer
平等必须是如此)