2016-03-08 165 views
2

我必須將對象與同一類的原始屬性進行比較。 意義,我要比較那些:。哪個更快?

struct Identifier 
{ 
    string name; 
    string email; 
} 

與兩個字符串的姓名和電子郵件。 我知道我可以爲名稱和電子郵件創建一個新的標識符實例,並將其傳遞給equals()。我的應用程序必須非常快速且節省資源。

我知道通過散列碼比較不是一個好方法,因爲如解釋here有碰撞。但碰撞對我來說沒問題,我只需要它快。

所以,

1)是通過GetHashCode的(比較檢查,如果兩個對象的哈希碼是相同的)的速度比的equals()?

2)我應該改爲創建一個新的比較兩個值的標識符實例,做一個新的方法,直接取值?例如

struct Identifier { 
    string name; 
    string email; 

    bool Equals(string name, string email) { 
     // todo comparison via hashcode or equals 
    } 
} 

I would use the Equals() and GetHashCode() method generated by resharper.

+0

GetHashCode不是用於相等比較,而是獲取哈希碼。 C#中的Hashcode是32位信息,而您的字符串在技術上可能包含無限量的信息。所以非常不同的字符串可能具有相同的哈希碼。推薦閱讀 - http://stackoverflow.com/questions/371328/why-is-it-important-to-override-gethashcode-when-equals-method-is-overridden –

+0

請問C#緩存一個字符串的hashCode?因爲如果你必須實時計算它,那比比較兩個字符串要慢。 – Thilo

+0

@Thilo [不,它不](http://referencesource.microsoft.com/#mscorlib/system/string.cs,0a17bbac4851d0d4)。但是計算兩個字符串的哈希代碼非常快,您應該在自己的'GetHashCode'實現中使用它們。 –

回答

3

如果將它們保存在Identifier實例上(見下文),比較哈希碼可能會更快。然而,與平等比較並不是一回事。

通過比較哈希代碼,您可以檢查兩個項目是否確實是而不是彼此相等:當您獲得不同的哈希代碼時您會知道這一點。

但是,當哈希碼相等時,您不能對等式做出明確聲明:項目可能相等或不相等。這就是爲什麼基於散列的容器必須總是遵循散列碼比較,直接或間接比較相等性。

嘗試實施這樣的比較:

struct Identifier { 
    string name; 
    string email; 
    int nameHash; 
    int emailHash; 
    public Identifier(string name, string email) { 
     this.name = name; 
     nameHash = name.GetHashCode(); 
     this.email = email; 
     emailHash = email.GetHashCode(); 
    } 
    bool Equals(string name, string email) { 
     return name.GetHashCode() == nameHash 
      && email.GetHashCode() == emailHash 
      && name.equals(this.name) 
      && email.equals(this.email); 
    } 
} 

相較於預先計算哈希碼將會短路的實際平等比較,這樣你就可以節省一些CPU週期時,大部分的比較結束返回false

+1

爲什麼計算兩個哈希碼比比較兩個字符串更快?兩者似乎都必須迭代字符串(並且比較可能會在第一個不匹配字符上短路)。 – Thilo

+1

@Thilo確實不是更快。要查看2個對象是否相等,可以調用Equals方法,這就是全部。 GetHashCode只是用來在散列集合(HashSet,Dictionary ...)中「排序」(有點)你的對象,以便能夠以O(1)的複雜度找到它。 – krimog

+0

@Thilo我確信C#高速緩存的字符串哈希代碼的Java方式,但快速檢查的來源告訴我,我錯了:.NET設計師去保存內存。計算哈希代碼在CPU高速緩存方面略有優勢,因爲代碼是從順序位置讀取的,因此大多數讀取操作都是高速緩存命中。但是,這隻適用於很長的字符串,即使這樣,影響也很小。無論如何,我改變了答案的措辭,並建議一個明確緩存哈希代碼的實現。 – dasblinkenlight

4

經由GetHashCode的比較(檢查,如果兩個對象 的哈希碼是相同的)比的Equals更快()?

你似乎混淆了這兩個概念。 GetHashCode的目的不是尋求兩個對象實例之間的相等,它只是在那裏,因此每個對象都可以輕鬆地爲可能在其上進行中繼的任何外部資源提供散列碼值。

Equals另一方面,是否有確定平等。應該是兩個產生相等的true的方法提供相同的哈希碼,但不是相反。

The documentation on object.GetHashCode提供了一個很好的解釋:

兩個對象是相等的回報相同的散列碼。然而, 的情況卻並非如此:相同的散列碼並不意味着對象 相等,因爲不同的(不相等的)對象可以具有相同的散列碼 代碼。此外,.NET Framework不保證GetHashCode方法的默認 實現,並且此方法 返回的值可能在.NET Framework版本和平臺(如 與32位和64位平臺)之間有所不同。由於這些原因,請勿將此方法的默認實現用作散列目的的唯一對象標識符 。由此產生兩個後果:

  • 您不應該假設相同的散列碼暗示對象相等。
  • 您永遠不應該在其創建的應用程序域 之外堅持或使用哈希碼,因爲同一對象可能在應用程序域,進程和平臺上散列。

如果你想兩個實例之間檢查平等,我絕對推薦實施IEquatable<T>和壓倒一切的object.GetHashCode

作爲一個備註 - 我看到你正在使用struct。你應該注意到struct在C#中的語義不同於C++或C,我希望你知道它們。