Daniel
Daniel

Reputation: 3868

Custom hashable struct for my Dictionary

I'd like to build a hashable value to be used for my dictionary's key. It should consist of a structure with two strings and an NSDate. I'm not sure I built my hashValue getter correctly below:

// MARK: comparison function for conforming to Equatable protocol
func ==(lhs: ReminderNotificationValue, rhs: ReminderNotificationValue) -> Bool {
    return lhs.hashValue == rhs.hashValue
}
struct ReminderNotificationValue : Hashable {
    var notifiedReminderName: String
    var notifiedCalendarTitle: String
    var notifiedReminderDueDate: NSDate

var hashValue : Int {
    get {
        return notifiedReminderName.hashValue &+ notifiedCalendarTitle.hashValue &+ notifiedReminderDueDate.hashValue
    }
}

init(notifiedReminderName: String, notifiedCalendarTitle: String, notifiedReminderDueDate: NSDate) {
    self.notifiedReminderName = notifiedReminderName
    self.notifiedCalendarTitle = notifiedCalendarTitle
    self.notifiedReminderDueDate = notifiedReminderDueDate
}
}


var notifications: [ReminderNotificationValue : String] = [ : ]

let val1 = ReminderNotificationValue(notifiedReminderName: "name1", notifiedCalendarTitle: "title1", notifiedReminderDueDate: NSDate())
let val2 = ReminderNotificationValue(notifiedReminderName: "name1", notifiedCalendarTitle: "title1", notifiedReminderDueDate: NSDate())

notifications[val1] = "bla1"
notifications[val2] = "bla2"

notifications[val2]   // returns "bla2". 
notifications[val1]   // returns "bla1". But I'd like the dictionary to overwrite the value for this to "bla2" since val1 and val2 should be of equal value.

Upvotes: 0

Views: 178

Answers (1)

Martin R
Martin R

Reputation: 539745

The problem is not your hashValue implementation, but the == function. Generally, x == y implies x.hashValue == y.hashValue, but not the other way around. Different objects can have the same hash value. Even

var hashValue : Int { return 1234 }

would be an ineffective, but valid hash method.

Therefore in ==, you have to compare the two objects for exact equality:

func ==(lhs: ReminderNotificationValue, rhs: ReminderNotificationValue) -> Bool {
    return lhs.notifiedReminderName == rhs.notifiedReminderName
    && lhs.notifiedCalendarTitle == rhs.notifiedCalendarTitle
    && lhs.notifiedReminderDueDate.compare(rhs.notifiedReminderDueDate) == .OrderedSame
}

Another problem in your code is that the two invocations of NSDate() create different dates, as NSDate is an absolute point in time, represented as a floating point number with sub-second precision.

Upvotes: 1

Related Questions