swift - 字段子集上的 CollectionDifference
问题描述
考虑以下代码片段,它创建了 2 个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
字段更改col2
为 2
var col2 = [
Foo(v: "a", other: 2),
Foo(v: "c", other: 2),
Foo(v: "d", other: 2),
]
由于我仅从 生成哈希值v
,因此我希望得到相同的输出,但我实际得到的是这个。
remove: 2
remove: 1
remove: 0
insert: 0
insert: 1
insert: 2
我在这里想念什么?
解决方案
BidirectionalCollection.difference(from:)
根据元素的相等性计算两个集合的“差异”。由于您没有实现==
for Foo
,因此编译器会合成一个默认实现,并比较所有(存储的)属性。
采用该Hashable
协议可以提高性能,但不影响值的相等性:不同的元素可以具有相同的哈希值。
如果您提供我们自己的Equatable
as实现
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 })
推荐阅读
- django - gitlab 使用 django 和 postgres 运行 ci 测试
- groovy - 如何使用 groovy 创建 HTTP/2 连接
- python - scikit 管道中的 LeaveOneOut 编码器
- vba - 将本地 MS Access 数据库中的表记录插入 Oracle 表
- java - 在 Java 语言规范版本 11 的第 4.10.2 节中,包含通配符的参数化类型是否没有直接超类型?
- reactjs - 反应测试库
- swift - 无效的捆绑包。您的二进制文件 {Bundle name} 具有 64 位架构切片
- python - 如何通过 Python 和 Web3.py 获取 ETH 智能合约的数量?
- python - 嵌套循环将多个函数的结果收集到单独的 DataFrame 挑战中
- javascript - CSS渐变背景动画没有动画