这是尝试实现 Dave DeLong 的文章 Edit distance and edit steps 中概述的解决方案。
Changeset
描述了将一个 Equatable
元素的 Collection
转换为另一个 Collection
所需的最小编辑操作。
它的主要目的是与 UITableView
和 UICollectionView
数据源结合使用,通过检测两个数据集之间的添加、删除、替换和移动操作。但它也可以用于计算两个数据集之间更通用的更改。
以下代码计算了规范示例的最小编辑操作,将 String
集合从 “kitten” 转换为 “sitting”
let changeset = Changeset(source: "kitten", target: "sitting")
print(changeset)
// 'kitten' -> 'sitting':
// replace with s at offset 0
// replace with i at offset 4
// insert g at offset 6
以下断言将会成功
let edits = [
Changeset<String>.Edit(operation: .substitution, value: "s", destination: 0),
Changeset<String>.Edit(operation: .substitution, value: "i", destination: 4),
Changeset<String>.Edit(operation: .insertion, value: "g", destination: 6),
]
assert(changeset.edits == edits)
如果您不想要 Changeset
本身的开销(它还会存储源集合和目标集合),您可以直接调用 edits
(此处使用了来自 Apple 示例数据,出自 iOS Table View Programming Guide)
let source = ["Arizona", "California", "Delaware", "New Jersey", "Washington"]
let target = ["Alaska", "Arizona", "California", "Georgia", "New Jersey", "Virginia"]
let edits = Changeset.edits(from: source, to: target)
print(edits)
// [insert Alaska at offset 0, replace with Georgia at offset 2, replace with Virginia at offset 4]
请注意,Changeset 使用偏移量而不是索引来引用集合中的元素。这主要是因为 Swift 集合不保证使用从零开始的整数索引。有关更多详细信息,请参阅 issue #37 中的讨论。
偏移量值可以直接在 UITableView
上的 beginUpdates
/endUpdates
和 UICollectionView
上的 performBatchUpdates
的动画块中使用,因为 Changeset
遵循 Apple 指南中 批量插入、删除和重新加载行和节 下解释的原则。
简而言之;首先相对于源集合进行所有删除和替换,然后相对于结果集合进行插入。移动只是一个删除后跟一个插入。
在 iOS 框架中,包含了两个便捷扩展(一个在 UITableView
上,一个在 UICollectionView
上),使动画表格/集合视图更新变得轻而易举。只需调用 update
,就像这样
tableView.update(with: changeset.edits)
默认情况下,Changeset
使用 ==
来比较元素,但您可以编写自己的比较器,如下所示,其中 “a” 的出现始终会触发更改
let alwaysChangeA: (Character, Character) -> Bool = {
if $0 == "a" || $1 == "a" {
return false
} else {
return $0 == $1
}
}
let changeset = Changeset(source: "ab", target: "ab", comparator: alwaysChangeA)
因此,changeset 将包含将 “a” 替换为另一个 “a” 的操作
let expectedEdits: [Changeset<String>.Edit] = [Changeset.Edit(operation: .substitution, value: "a", destination: 0)]
assert(changeset.edits == expectedEdits)
一种可能的用途是当 UITableView
或 UICollectionView
中的单元格在更改时不应动画时。
Xcode 项目还包含一个目标,用于说明在应用程序中的用法
这使用上面提到的扩展来基于 Changeset
的编辑操作来动画过渡。
本项目根据 MIT 许可证 提供。
版权所有 © 2015-18, Joachim Bondo。请参阅 LICENSE 文件。