This code will generate different result when RoadmapCardChain implement Hashable and Equatable protocol
sometime result is :
but sometime result is :
I don't know why same codes has different performance
I still don't understand why sometimes == be called and sometimes it doesn't be called。According to my understanding Set only need hashvalue when insert or contains function, don't need to call ==
Code Block struct RoadmapCardChain: Codable, Hashable, Equatable { let start: String let end: String let styles: String static func == (lhs: RoadmapCardChain, rhs: RoadmapCardChain) -> Bool { let isStyleSame = lhs.styles == rhs.styles let isEndSame = lhs.start == rhs.start && lhs.end == rhs.end let isToggleEndSame = lhs.start == rhs.end && lhs.end == rhs.start print(lhs) print(rhs) print("result is \(isStyleSame && ( isEndSame isToggleEndSame ))") return isStyleSame && ( isEndSame isToggleEndSame ) } } let a = RoadmapCardChain(start: "Cafeteria", end: "Payment BIZ", styles: "AECC5C") let b = RoadmapCardChain(start: "Payment BIZ", end: "Cafeteria", styles: "AECC5C") var chains: Set<RoadmapCardChain> = [] print(a.hashValue) print(b.hashValue) chains.insert(a) if chains.contains(b) { print("contains is true") } else { chains.insert(b) } print(chains)
sometime result is :
Code Block 785027920194053578 6404817261741129101 RoadmapCardChain(start: "Cafeteria", end: "Payment BIZ", styles: "AECC5C") RoadmapCardChain(start: "Payment BIZ", end: "Cafeteria", styles: "AECC5C") result is true contains is true [__lldb_expr_19.RoadmapCardChain(start: "Cafeteria", end: "Payment BIZ", styles: "AECC5C")]
but sometime result is :
Code Block 491382166321900052 7275567105868021174 [lldb_expr_21.RoadmapCardChain(start: "Cafeteria", end: "Payment BIZ", styles: "AECC5C"), lldb_expr_21.RoadmapCardChain(start: "Payment BIZ", end: "Cafeteria", styles: "AECC5C")]
I don't know why same codes has different performance
I still don't understand why sometimes == be called and sometimes it doesn't be called。According to my understanding Set only need hashvalue when insert or contains function, don't need to call ==
Seems your understanding is wrong.According to my understanding Set only need hashvalue when insert or contains function, don't need to call ==
hashValue for different (meaning not ==) values may have the same value. So Set needs to call == in some cases, including when inserting or checking contained.
When a.hashValue ≠ b.hashValue, it is guaranteed that a ≠ b, so Set has no need to call ==. But when a.hashValue == b.hashValue, Set needs to call == to check if a == b or not.
That means, hashValue and == need to be consistent, which is represented by a simple axiom:
When a == b, a.hashValue must be equal to b.hashValue.
Your current implementation does not fulfill this axiom.
Please try this:
Code Block struct RoadmapCardChain: Codable, Hashable, Equatable { let start: String let end: String let styles: String static func == (lhs: RoadmapCardChain, rhs: RoadmapCardChain) -> Bool { let isStyleSame = lhs.styles == rhs.styles let isEndSame = lhs.start == rhs.start && lhs.end == rhs.end let isToggleEndSame = lhs.start == rhs.end && lhs.end == rhs.start print(lhs) print(rhs) print("result is \(isStyleSame && ( isEndSame ‖ isToggleEndSame ))") return isStyleSame && ( isEndSame ‖ isToggleEndSame ) } //To make `hashValue` consistent with `==` above func hash(into hasher: inout Hasher) { styles.hash(into: &hasher) if start <= end { start.hash(into: &hasher) end.hash(into: &hasher) } else { end.hash(into: &hasher) start.hash(into: &hasher) } } }
(Seems this site removes from inside code blocks. I have replaced to U+2016 ‖. If you want to use my code above, you need to replace U+2016 ‖ to ||.)