2009-07-02 3 views
5

Về cơ bản, tôi đã sau cho đến nay:Làm thế nào tôi nên đi về việc thực hiện Object.GetHashCode() cho sự bình đẳng phức tạp?

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; 
    } 
} 

Vì vậy, vấn đề là thế này: Tôi có một tổ chức phi Bắt buộc điền vào Guid, mà là một định danh duy nhất. Nếu điều này không được thiết lập, thì tôi cần phải cố gắng xác định sự bình đẳng dựa trên các số liệu ít chính xác hơn như là một nỗ lực để xác định xem hai đối tượng có bình đẳng không. Điều này làm việc tốt, nhưng nó làm cho GetHashCode() lộn xộn ... Làm thế nào tôi nên đi về nó? Triển khai ngây thơ sẽ giống như sau:

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; 
} 

Nhưng cơ hội của hai loại băm va chạm là gì? Chắc chắn, tôi sẽ không mong đợi nó là 1 in 2 ** 32. Đây có phải là một ý tưởng tồi, và nếu có, tôi nên làm như thế nào?

+0

Điều quan trọng hơn là thuật toán băm của bạn đồng ý với thuật toán bình đẳng của bạn so với phân phối đồng đều. Hãy nhớ rằng, mục đích của băm là chỉ để có được một bản phân phối tốt trong một bảng băm; miễn là bạn không ồ ạt xiên vào một thùng cụ thể, tỷ lệ cược là tốt, bạn sẽ ổn thôi. Nếu bạn quan tâm, hãy chọn một kịch bản hợp lý mà người tiêu dùng của đối tượng của bạn có khả năng gặp phải - giả sử, đặt vài trăm từ trong từ điển, nếu điều đó hợp lý - và thực hiện một số thử nghiệm perf để xem bạn có chấp nhận được không các kết quả. –

+0

Điều tôi từng thấy trong thực tế sử dụng là ~ 200, nhưng việc sử dụng điển hình là <30, vì vậy bạn có thể đúng. –

+1

Heck, với dưới 30 mục, tìm kiếm tuyến tính trong danh sách được liên kết có thể là một người thực hiện hợp lý. Bạn có thể trả lại mã băm bằng 0, luôn có 100% cơ hội va chạm và vẫn nhận được hiệu suất chấp nhận được. Điểm của việc phân phối mã băm tốt là tạo ra quy mô hiệu suất khi kích thước từ điển trở nên lớn. Bạn có thể có một bản phân phối tệ hại và vẫn nhận được kết quả tốt nếu bạn chỉ sẽ đặt một số lượng nhỏ các mục trong bảng. –

Trả lời

4

Tôi không nghĩ rằng có vấn đề với cách tiếp cận mà bạn đã chọn sử dụng. Lo lắng 'quá nhiều' về va chạm băm hầu như luôn là dấu hiệu của việc suy nghĩ quá mức về vấn đề; miễn là băm có nhiều khả năng khác nhau, bạn nên ổn.

Cuối cùng, bạn thậm chí có thể muốn xem xét việc bỏ số Description khỏi mã băm của bạn nếu có lý do để cho rằng hầu hết các đối tượng thời gian có thể được phân biệt dựa trên tiêu đề và ngày xuất bản (sách?).

Bạn thậm chí có thể xem xét việc bỏ qua GUID trong hàm băm của mình hoàn toàn và chỉ sử dụng nó trong triển khai Equals để phân biệt trường hợp không (?) Của các xung đột băm.

+0

Altho, rõ ràng là GUID nếu có, có khả năng băm nhanh hơn rất nhiều so với chuỗi tiêu đề tùy ý ... vì vậy nó có thể là một tối ưu hóa hiệu suất khả thi. – jerryjvl

+0

Mô tả cần được bao gồm trong sự bình đẳng (và do đó trong mã băm) –

+0

Ồ, và đối với bản ghi, các mục RSS. –

7

Rất dễ dàng hash code method for custom classes là bit XOR mỗi mã băm của các trường cùng nhau. Nó có thể đơn giản như thế này:

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

Từ link above:

XOR có các tính chất thoải mái sau:

  • Nó không phụ thuộc vào thứ tự tính toán.
  • Nó không "lãng phí" bit. Nếu bạn thay đổi ngay cả một bit trong một trong các thành phần, giá trị cuối cùng sẽ thay đổi.
  • Nhanh chóng, một chu kỳ đơn lẻ trên máy tính nguyên thủy nhất.
  • Nó bảo quản phân phối đồng đều. Nếu hai phần bạn kết hợp được phân bố đều nhau thì sự kết hợp sẽ là như thế. Nói cách khác, nó không có xu hướng thu hẹp phạm vi của tiêu hóa vào một dải hẹp hơn.

XOR không hoạt động tốt nếu bạn muốn có giá trị trùng lặp trong trường của mình dưới dạng giá trị trùng lặp sẽ hủy nhau khi XOR. Vì bạn đang băm cùng nhau ba trường không liên quan nên không phải là vấn đề trong trường hợp này.

+7

XOR không phụ thuộc vào thứ tự tính toán là một thanh kiếm hai lưỡi ... nếu bạn có đối tượng với nhiều trường cùng loại (ví dụ, hai ngày), thì khi chúng được hoán đổi quanh các đối tượng sẽ 'trông giống nhau 'để băm. – jerryjvl