2009-01-14 33 views
10

Tài liệu cho -hash nói rằng nó không được thay đổi trong khi đối tượng có thể thay đổi được lưu trữ trong bộ sưu tập, và tài liệu tương tự cho -isEqual: nói giá trị -hash phải giống nhau.Các kỹ thuật để thực hiện -hash trên các đối tượng Cacao có thể thay đổi

Với điều này, không ai có bất kỳ đề xuất nào về cách tốt nhất để triển khai -hash sao cho nó đáp ứng cả hai điều kiện này nhưng thực sự được tính toán thông minh (tức là không chỉ trả lại 0)? Có ai biết làm thế nào các phiên bản có thể thay đổi của các lớp khung cung cấp làm điều này? Điều đơn giản nhất là chỉ cần quên điều kiện đầu tiên (về nó không thay đổi) và chỉ cần chắc chắn rằng tôi không bao giờ vô tình biến đổi một đối tượng trong khi nó trong một bộ sưu tập, nhưng tôi tự hỏi nếu có bất kỳ giải pháp đó là nhiều hơn nữa Linh hoạt.

EDIT: Tôi tự hỏi ở đây liệu có thể duy trì 2 hợp đồng hay không. trạng thái của đối tượng. Độ nghiêng của tôi là để nói "không", trừ khi tôi làm điều gì đó ngu ngốc như luôn luôn trả về 0 cho băm, nhưng đó là lý do tại sao tôi hỏi câu hỏi này.

+0

đoán đây là một câu hỏi cũ, chỉ tìm thấy nó ... nhưng không phải là đối tượng có thể thay đổi được sử dụng làm khóa trong bộ sưu tập thường được sao chép? Điều đó không chỉ cản trở vấn đề? – nielsbot

+0

@nielsbot: Chỉ các khóa cho NSDictionaries mới được sao chép. NSSet không sao chép các đối tượng của nó và API 'CFDictionarySetValue()' cũng không sao chép khóa của nó. –

+0

'CFDictionarySetValue' sẽ làm gì nếu bạn chuyển' kCFTypeDictionaryKeyCallbacks' thành 'CFDictionaryCreate', không? Các tài liệu gần như không nhạy cảm ... Tôi cho rằng một bộ sưu tập có thể thay đổi obj có thể, uh, cache các giá trị băm, giống như giả định một obj có thể thay đổi trong một bộ sưu tập sẽ không thay đổi giá trị băm của nó, đúng không? – nielsbot

Trả lời

2

Thú vị câu hỏi, nhưng tôi nghĩ rằng những gì bạn muốn là một cách logic không thể. Giả sử bạn bắt đầu với 2 đối tượng, A và B. Chúng đều khác nhau và bắt đầu bằng các mã băm khác nhau. Bạn thêm cả hai vào một số bảng băm. Bây giờ, bạn muốn thay đổi A, nhưng bạn không thể thay đổi mã băm vì nó đã có trong bảng. Tuy nhiên, có thể thay đổi A theo cách sao cho nó bằng nhau() B.

Trong trường hợp này, bạn có 2 lựa chọn, không ai trong số đó hoạt động:

  1. Thay đổi hashcode của A đến B.hashcode bình đẳng, vi phạm các hạn chế của việc không thay đổi mã băm trong khi ở một bảng băm.
  2. Không thay đổi mã băm, trong trường hợp này là A.equals (B) nhưng chúng không có cùng mã băm.

Dường như với tôi rằng không có cách nào để thực hiện việc này mà không sử dụng hằng số dưới dạng mã băm.

+0

Đó là những gì tôi nghĩ, và tôi đoán nó có lẽ đúng. –

-2

Trong Java, hầu hết các lớp có thể thay đổi chỉ đơn giản là không ghi đè Object.hashCode() để triển khai mặc định trả về giá trị dựa trên địa chỉ của đối tượng và không thay đổi. Nó chỉ có thể là cùng với Objective C.

+2

Ngoại trừ vi phạm quy tắc mà các đối tượng bằng nhau cần phải có cùng một băm. Việc triển khai mặc định cho -isEqual: chỉ so sánh con trỏ, nhưng tôi ghi đè nó để thực hiện so sánh dựa trên giá trị của các trường trong đối tượng. –

2

đọc của tôi về các tài liệu là giá trị của một đối tượng có thể thay đổi cho hashthể (và có lẽ nên) thay đổi khi nó được biến đổi, nhưng không nên thay đổi khi đối tượng chưa bị đột biến. Do đó, phần tài liệu cần tham khảo là "Không được thay đổi các đối tượng được lưu trữ trong bộ sưu tập, vì điều đó sẽ làm cho giá trị hash của chúng thay đổi".

Để trích dẫn trực tiếp từ NSObject documentation for hash:

Nếu một đối tượng có thể thay đổi được thêm vào một bộ sưu tập có sử dụng các giá trị băm để xác định vị trí của đối tượng trong bộ sưu tập , giá trị trả về bởi phương pháp băm của đối tượng không được thay đổi trong khi đối tượng nằm trong bộ sưu tập . Do đó, một trong hai phương pháp băm phải không dựa trên bất kỳ thông tin trạng thái nội bộ của đối tượng hoặc bạn phải chắc chắn thông tin trạng thái nội bộ của đối tượng không thay đổi trong khi các đối tượng đang trong bộ sưu tập.

(tôi nhấn mạnh).

+0

Vâng, đó là cách tôi đọc nó, nhưng nếu băm không dựa vào trạng thái bên trong làm cho nó khá khó để làm cho các đối tượng bằng nhau băm giống nhau. Đây là lý do tại sao tôi hỏi câu hỏi này, để tìm hiểu xem có ai có giải pháp thông minh để lưu trữ các đối tượng có thể thay đổi được trong bảng bản đồ hay không. –

+0

Nếu bạn đang tìm kiếm các thủ thuật thông minh cho điều này, tôi không nghĩ rằng tôi có thể trợ giúp, nhưng lưu ý rằng tài liệu nói rằng phương thức băm không được dựa vào trạng thái nội bộ * hoặc * trạng thái bên trong phải được đảm bảo không thay đổi trong khi trong bộ sưu tập. Bạn có thể sử dụng trạng thái bên trong nếu bạn tuân theo thứ hai. –

+0

Khi đọc lại câu hỏi: bạn có hỏi liệu có cách nào để giữ băm và isEqual: hợp đồng trong khi biến đổi một đối tượng trong bộ sưu tập hay chỉ là liệu có thể giữ hợp đồng nói chung không? Tôi đã trả lời câu hỏi thứ hai, đó có thể không phải là những gì bạn đang hỏi. –

0

Vì bạn đã ghi đè -quyền: để thực hiện so sánh dựa trên giá trị, bạn có chắc là bạn thực sự cần phải bận tâm với -hash không?

Tôi không thể đoán chính xác bạn cần gì cho khóa học, nhưng nếu bạn muốn so sánh dựa trên giá trị mà không bị lệch so với triển khai dự kiến ​​-isEqual: chỉ trả về YES khi hashes giống hệt nhau, cách tiếp cận tốt hơn có thể là bắt chước NSString's -isEqualToString :, để tạo phương thức -isEqualToFoo: của riêng bạn thay vì sử dụng hoặc ghi đè -isEqual :.

+1

Tài liệu giao thức NSObject cho trạng thái rõ ràng này ghi đè -isEqual: và không -hash là không chính xác và có thể gây ra sự cố khi một phiên bản của lớp được lưu trữ trong bộ sưu tập. Ngoài ra, NSString ghi đè -isEqual: để gọi -isEqualToString: nếu cả hai đối tượng là chuỗi. Xem tài liệu Apple này: http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html#//apple%5Fref/doc/uid/TP40002974-CH4-SW25 –

1

Câu hỏi đặt ra ở đây không phải là cách đáp ứng cả hai yêu cầu này, mà thay vào đó bạn cần đáp ứng. Trong tài liệu của Apple, rõ ràng là tuyên bố rằng:

từ điển có thể thay đổi có thể được đặt trong bảng băm nhưng bạn không được thay đổi trong khi ở trong đó.

Điều này đang được nói, có vẻ quan trọng hơn là bạn đáp ứng yêu cầu bình đẳng của băm. Hàm băm của một đối tượng luôn luôn là một cách để kiểm tra xem một đối tượng có bằng một đối tượng khác hay không. Nếu điều này không bao giờ xảy ra, nó không phải là hàm băm đúng.

Chỉ để kết thúc câu trả lời của tôi, tôi sẽ đưa ra ví dụ về triển khai băm tốt. Giả sử bạn đang viết triển khai -hash trên bộ sưu tập mà bạn đã tạo. Bộ sưu tập này lưu trữ một mảng các NSObjects làm con trỏ. Vì tất cả NSObjects thực hiện hàm băm, bạn có thể sử dụng băm của họ trong việc tính toán hash của bộ sưu tập:

- (NSUInteger)hash { 
    NSUInteger theHash = 0; 
    for (NSObject * aPtr in self) { // fast enumeration 
     theHash ^= [aPtr hash]; 
    } 
    return theHash; 
} 

Bằng cách này, hai đối tượng bộ sưu tập có chứa các con trỏ cùng (theo thứ tự) sẽ có cùng bảng băm.

Các vấn đề liên quan