字段子集的CollectionDifference

时间:2019-11-28 10:31:47

标签: swift

考虑以下代码片段,该代码片段创建了两个Foo结构集合的差异

struct Foo {

    let v: String
    let other: Int
}

extension Foo: Hashable {

    func hash(into hasher: inout Hasher) {
        hasher.combine(v)
    }
}

extension Foo: CustomStringConvertible {

    var description: String {
        return v
    }
}

var col1 = [
    Foo(v: "a", other: 1),
    Foo(v: "b", other: 1),
    Foo(v: "c", other: 1),
]

var col2 = [
    Foo(v: "a", other: 1),
    Foo(v: "c", other: 1),
    Foo(v: "d", other: 1),
]

let diff = col2.difference(from: col1)

diff.forEach { change in
    switch change {
    case let .remove(offset, _, _):
        print("remove: \(offset)")
    case let .insert(offset, _, _):
        print("insert: \(offset)")
    }
}

这将按预期产生以下print输出:

remove: 1
insert: 2

现在像这样将other的{​​{1}}字段更改为2

col2

由于我仅从var col2 = [ Foo(v: "a", other: 2), Foo(v: "c", other: 2), Foo(v: "d", other: 2), ] 中产生一个哈希值,所以我期望得到相同的输出,但是实际上是这样的。

v

我在这里想念什么?

1 个答案:

答案 0 :(得分:0)

BidirectionalCollection.difference(from:)根据两个集合的元素的平等计算两个集合的“差”。由于您没有为==实现Foo,因此编译器将合成一个默认实现,并比较所有(存储的)属性。

采用Hashable协议可以提高性能,但不会影响值的相等性:不同的元素可以具有相同的哈希值。

如果您提供我们自己的Equatable的实现方式

extension Foo: Equatable {
    static func ==(lhs: Foo, rhs: Foo) -> Bool {
        return lhs.v == rhs.v
    }
}

然后

Foo(v: "a", other: 1) == Foo(v: "a", other: 2) // etc.

并且输出是预期的

remove: 1
insert: 2

或者,使用``BidirectionalCollection.difference(from:by:)`并通过自定义等效测试:

let diff = col2.difference(from: col1, by: { $0.v == $1.v })