可散列自定义元素集插入相等的元素

Rei*_*ner 2 set hashable swift

设置:

\n

我想使用Set以下之一struct:

\n
struct NumberPair: Hashable {\n    let n1: Int\n    let n2: Int\n\n    static func == (lhs: NumberPair, rhs: NumberPair) -> Bool {\n        lhs.n1 == rhs.n1 && lhs.n2 == rhs.n2 ||\n        lhs.n2 == rhs.n1 && lhs.n1 == rhs.n2\n    }\n    \n    func hash(into hasher: inout Hasher) {\n        hasher.combine(n1)\n        hasher.combine(n2)\n    }\n}  \n
Run Code Online (Sandbox Code Playgroud)\n

我预计将两个相等的元素(根据上面定义的函数)插入到空Set结果中会Set产生一个元素:

\n
    var pairs: Set<NumberPair> = []\n//\xe2\x80\xa6\n    pairs.insert(NumberPair(n1: 1, n2: 2))\n    pairs.insert(NumberPair(n1: 2, n2: 1))  \n
Run Code Online (Sandbox Code Playgroud)\n

问题:

\n

但是,在第二次插入时我收到运行时错误

\n
Fatal error: Duplicate elements of type 'NumberPair' were found in a Set.\nThis usually means either that the type violates Hashable's requirements, or\nthat members of such a set were mutated after insertion.  \n
Run Code Online (Sandbox Code Playgroud)\n

当我在 中设置断点时static func ==,不会命中断点。

\n

问题:

\n

为什么我的自定义相等函数没有被调用,以及如何正确执行?

\n

Mar*_*n R 7

您的hash()方法违反了协议最重要的要求Hashable:

\n
\n

两个相等的实例必须以相同的顺序向 hash(into:) 中的 Hasher 提供相同的值。

\n
\n

例子:

\n
let p1 = NumberPair(n1: 1, n2: 2)\nlet p2 = NumberPair(n1: 2, n2: 1)\n\nprint(p1 == p2) // true\nprint(p1.hashValue) // -386759992433315259\nprint(p2.hashValue) // -5091661336101841357\n
Run Code Online (Sandbox Code Playgroud)\n

这里p1和p2是 \xe2\x80\x9cequal\xe2\x80\x9d 但产生不同的哈希值。

\n

哈希方法的实现方式必须能够在交换n1和n2时产生相同的结果,例如

\n
func hash(into hasher: inout Hasher) {\n    hasher.combine(min(n1, n2))\n    hasher.combine(max(n1, n2))\n}\n
Run Code Online (Sandbox Code Playgroud)\n

或者

\n
func hash(into hasher: inout Hasher) {\n    hasher.combine(n1 ^ n2)\n}\n
Run Code Online (Sandbox Code Playgroud)\n

备注:第二个更简单,也许更快,但更可能导致哈希冲突。struct Hasher及其combine(_:)在 Swift 4.2 中引入的方法(以及其他原因),以摆脱 \xe2\x80\x9cXOR 哈希,\xe2\x80\x9d 请参阅SE-0206 SEHashable 增强。

\n