简体   繁体   English

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

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

This question is similar to the one here . 这个问题类似于这里的问题

We all know what PointF is, don't we? 我们都知道PointF是什么,不是吗? This is the data structure: 这是数据结构:

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

How to implement IEqualityComparer<PointF> with tolerance? 如何实现具有容差的IEqualityComparer<PointF> Let's say my Equals code is like this 假设我的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;
}

Question: How to implement the correct GetHashCode so that for a dictionary of PointF , I will access the element correctly? 问题:如何实现正确的GetHashCode以便对于PointF的字典,我将正确访问该元素?

I crack my head a few days but still can't find a satisfactory solution. 我几天头脑裂开但仍然无法找到满意的解决方案。

Instead of defining the tolerance by the distance, you could place the points in a grid. 您可以将点放在网格中,而不是通过距离定义公差。
If two points are in the same cell, they're considered equal and have the same hash code. 如果两个点在同一个单元格中,则它们被认为是相等的并且具有相同的哈希码。

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
}

Thesis: There is no implementation of Equals and GetHashCode that meets your requirements. 论文:没有满足您要求的EqualsGetHashCode实现。

Proof: Consider the following three points, A, B, and C: 证明:考虑以下三点,A,B和C:

插图

As per your requirements, 根据您的要求,

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)

But from (iv) and (v) follows 但是从(iv)和(v)开始

GetHashCode(A) == GetHashCode(C)

and thereby 从而

Equals(A, C) == true

which contradicts (iii) and (vi). 这与(iii)和(vi)相矛盾。

Since Equals and GetHashCode cannot return different values for the same arguments, there is no implementation that meets your requirements. 由于EqualsGetHashCode不能为相同的参数返回不同的值,因此没有满足您要求的实现。 qed QED

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

Well, the answer based on grids is good, but sometimes you need to group the close points anyway, even if they are not in the same grid cell. 嗯,基于网格的答案是好的,但有时你需要将关闭点分组,即使它们不在同一个网格单元格中。 My approach is to implement this with a grouping: two points are in the same group if either they are close or there is a sequence of close points connecting them. 我的方法是通过分组来实现这一点:如果它们接近或者有一系列连接它们的关闭点,则两个点在同一组中。 This semantics cannot be done with a proper IEqualityComparer , because it needs to know all the items in advance before producing the groups. 使用适当的IEqualityComparer无法完成此语义,因为它需要在生成组之前事先知道所有项目。 So I've done a simple LINQ-style operator GroupByCluster , which basically achieves this. 所以我做了一个简单的LINQ风格的运算符GroupByCluster ,基本上实现了这一点。

The code is here: http://ideone.com/8l0LH . 代码在这里: http//ideone.com/8l0LH It compiles on my VS 2010, but fails to compile on Mono because HashSet<> cannot be implicitly converted to IEnumerable<> (why?). 它在我的VS 2010上编译,但无法在Mono上编译,因为HashSet<>无法隐式转换为IEnumerable<> (为什么?)。

The approach is generic and thus not very efficient: it's quadratic on input size. 该方法是通用的,因此效率不高:它是输入大小的二次方。 For the concrete types it can be made more efficient: for example, for T = double we can just sort the input array and have O(n log n) performance. 对于具体类型,可以使其更有效:例如,对于T = double,我们可以对输入数组进行排序并具有O(n log n)性能。 The analogous though more complicated trick is applicable for 2D points as well. 类似但更复杂的技巧也适用于2D点。


Note aside: your initial proposition is impossible to implement with IEqualityComparer , since your "approximate equality" is not transitive (but the equality in IEqualityComparer has to be so). 请注意:您的初始命题不可能使用IEqualityComparer实现,因为您的“近似相等”不是可传递的(但IEqualityComparer的相等必须如此)。

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

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