簡體   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