2009-07-02 51 views
5

基本上,我已迄今以下:我應該如何去實現Object.GetHashCode()以實現複雜的相等性?

class Foo { 
    public override bool Equals(object obj) 
    { 
     Foo d = obj as Foo ; 
     if (d == null) 
      return false; 

     return this.Equals(d); 
    } 

    #region IEquatable<Foo> Members 

    public bool Equals(Foo other) 
    { 
     if (this.Guid != String.Empty && this.Guid == other.Guid) 
      return true; 
     else if (this.Guid != String.Empty || other.Guid != String.Empty) 
      return false; 

     if (this.Title == other.Title && 
      this.PublishDate == other.PublishDate && 
      this.Description == other.Description) 
      return true; 

     return false; 
    } 
} 

所以,問題是這樣的:我有一個非必需的字段Guid,這是一個唯一標識。如果沒有設置,那麼我需要嘗試根據不太精確的度量來確定相等性,以此來確定兩個對象是否相等。這工作正常,但它使GetHashCode()凌亂......我應該怎麼辦呢?一個天真的執行會是這樣的:

public override int GetHashCode() { 
    if (this.Guid != String.Empty) 
     return this.Guid.GetHashCode(); 

    int hash = 37; 
    hash = hash * 23 + this.Title.GetHashCode(); 
    hash = hash * 23 + this.PublishDate.GetHashCode(); 
    hash = hash * 23 + this.Description.GetHashCode(); 
    return hash; 
} 

但是兩種類型的哈希碰撞的機會是什麼?當然,我不希望它是1 in 2 ** 32。這是一個壞主意,如果是這樣,我該怎麼做呢?

+0

更重要的是,您的散列算法與您的相等算法一致,而不是分佈均勻。請記住,散列的目的僅僅是爲了在散列表中獲得一個體面的分佈;只要你沒有大規模傾向於一個特定的桶,賠率是好的,你會好起來的。如果你擔心,選擇一個合理的情景,你的對象的消費者可能會遇到 - 比方說,將其中的幾百個放在字典中,如果這是合理的 - 並進行一些性能測試,看看你是否可以接受結果。 – 2009-07-02 02:15:42

+0

我在實際使用中見過的最多是〜200,但通常使用<30,所以你可能是對的。 – 2009-07-02 03:02:13

+1

哎呀,在30項以下的情況下,鏈表中的線性搜索可能是合理的表現。你可以總是返回一個零的哈希碼,有100%的碰撞機會,並且仍然可以得到可接受的性能。散列碼分配良好的一點是,當字典大小變大時,可以提高性能。如果只打算在表格中放入少量項目,則可能會出現糟糕的分佈情況,並且仍然會取得良好效果。 – 2009-07-02 18:20:21

回答

4

我不認爲您選擇使用的方法存在問題。對散列衝突感到「太多」幾乎總是表明對問題的過度思考;只要散列很可能不同,你應該沒問題。

如果可以合理地預期大多數時間對象可以根據其標題和出版日期(書籍?)進行區分,那麼最終您甚至可以考慮從散列中排除Description

您甚至可以考慮忽略散列函數中的GUID,並且僅在Equals實現中使用它來消除不太可能(?)的散列衝突情況。

7

非常容易的hash code method for custom classes是將每個字段的哈希碼按位異或。它可以是如此簡單:

int hash = 0; 
hash ^= this.Title.GetHashCode(); 
hash ^= this.PublishDate.GetHashCode(); 
hash ^= this.Description.GetHashCode(); 
return hash; 

link above

XOR具有以下良好特性:

  • 它不依賴於計算的順序。
  • 它不會「浪費」位。如果您更改其中一個組件的一個位,則最終的值將會改變。
  • 即使在最原始的計算機上,它也是快速,單一的循環。
  • 它保持均勻分佈。如果你合併的兩部分是均勻分佈的,那麼組合是如此。換句話說,它並不傾向於將摘要的範圍縮小到更窄的範圍。如果你希望在你的字段中的重複值的重複值會相互抵消時的異或

XOR不能很好地工作。由於您將三個不相關的字段散列在一起,所以在這種情況下應該不會成爲問題。

相關問題