-
-
Save papertigers/516fae77bb0509712c58c9ecefb9746a to your computer and use it in GitHub Desktop.
Utility for diffing two arrays of arrays.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
enum DiffModification<T: Equatable> { | |
case inserted(position: NSIndexPath, value: T) | |
case deleted(position: NSIndexPath, value: T) | |
case moved(position: NSIndexPath, newPosition: NSIndexPath, value: T) | |
} | |
extension DiffModification: CustomDebugStringConvertible { | |
var debugDescription: String { | |
switch self { | |
case .inserted(let position, let value): | |
return "Inserted \(value) at \(position.section):\(position.item)" | |
case .deleted(let position, let value): | |
return "Deleted \(value) at \(position.section):\(position.item)" | |
case .moved(let position, let newPosition, let value): | |
return "Moved \(value) from \(position.section):\(position.item) to \(newPosition.section):\(newPosition.item)" | |
} | |
} | |
} | |
struct Diff<T: Equatable> { | |
let newCollection: [[T]] | |
let oldCollection: [[T]] | |
init(new: [[T]], old: [[T]]) { | |
self.oldCollection = old | |
self.newCollection = new | |
} | |
lazy var diff: [DiffModification<T>] = { | |
let newMap = self.diffMap(self.newCollection) | |
let oldMap = self.diffMap(self.oldCollection) | |
var oldItemsHandled = [T]() | |
var log = newMap.map({ (indexPath, item) -> DiffModification<T>? in | |
guard let oldIndex = oldMap.indexOf({ indexPath, question in question == item }) else { | |
return .inserted(position: indexPath, value: item) | |
} | |
defer { oldItemsHandled.append(item) } | |
let oldItemPosition = oldMap[oldIndex].0 | |
let oldItemValue = oldMap[oldIndex].1 | |
// Return now if the item has not moved | |
if oldItemPosition == indexPath { return nil } | |
return .moved(position: oldItemPosition, newPosition: indexPath, value: item) | |
}).flatMap { $0 } | |
log += oldMap.filter({ indexPath, item in | |
return oldItemsHandled.indexOf(item) == nil | |
}).map({ indexPath, item in | |
return DiffModification.deleted(position: indexPath, value: item) | |
}) | |
return log | |
}() | |
private func diffMap(collection: [[T]]) -> [NSIndexPath: T] { | |
var map = [NSIndexPath: T]() | |
for section in 0..<collection.count { | |
for item in 0..<collection[section].count { | |
let indexPath = NSIndexPath(forItem: item, inSection: section) | |
map[indexPath] = collection[section][item] | |
} | |
} | |
return map | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment