[英]How to recursively compare two Codable objects and get differences in Swift?
我有兩個Lecture
實例,它們是oldLecture
和newLecture
。 Lecture
的簡化聲明如下(完整版有更多字段):
struct Lecture: Codable {
let title: String
let class_times: [ClassTime]
let color: [String: String]
}
struct ClassTime: Codable {
let start: Double
let len: Double
}
現在我需要遞歸地比較oldLecture
和newLecture
,並創建一個新的類字典對象,該對象只包含在newLecture
中修改的屬性。 生成的對象將作為PUT
請求發送到服務器。
例如,
var oldLecture = Lecture(title: "lecture1",
class_times: [ClassTime(start: 1, len: 2)],
color: ["fg": "#fff", "bg": "#000"])
var newLecture = Lecture(title: "lecture1",
class_times: [ClassTime(start: 2, len: 3)],
color: ["fg": "#fff", "bg": "#000"])
// the result object should only contain `class_times` key with the value of `[ClassTime(start: 2, len: 3)]`
guard let oldDict = oldLecture.asDictionary() else { return nil }
guard let newDict = newLecture.asDictionary() else { return nil }
var dict: [String: Any] = [:]
for (key, newVal) in newDict {
if let oldVal = oldDict[key], oldVal != newVal {
dict[key] = newVal
}
}
上面的方法不起作用,因為它不會遞歸地比較oldVal
和newVal
。
有沒有更簡潔的方法來實現這一點,而不使用SwiftyJSON
等第三方庫?
您可以輕松地比較兩個結構
struct Lecture {
let title: String
let class_times: [ClassTime]
let color: [String: String]
static func == (lhs: Lecture, rhs: Lecture) -> Bool {
return lhs.title == rhs.title && lhs.class_times == rhs.class_times && lhs.color == rhs.color
}
}
struct ClassTime: Codable,Equatable {
let start: Double
let len: Double
}
以及如何比較
var oldLecture = Lecture(title: "lecture1",
class_times: [ClassTime(start: 1, len: 2)],
color: ["fg": "#fff", "bg": "#000"])
var newLecture = Lecture(title: "lecture1",
class_times: [ClassTime(start: 2, len: 3)],
color: ["fg": "#fff", "bg": "#000"])
func checkEquality() {
var dict: [String: Any] = [:]
if oldLecture != newLecture {
dict = newLecture.asDictionary()
}
print(dict)
}
要獲取 newLecture 和 oldLecture 之間的所有差異(反之亦然),並將其發送到您的服務器,請嘗試使用Equatable
for ClassTime
的這種方法,這將比較ClassTime
對象的內容。 getDiff(...)
的結果為您提供了一個Lecture
,在title
字段中具有標題差異,對於color
和class_times
字段也是如此。
let result = getDiff(old: oldLecture, new: newLecture)
print("\n---> result: \(result)")
do {
let data = try JSONEncoder().encode(result)
print("---> data: \(data)")
// --> send data to your server
if let str = String(data: data, encoding: .utf8) {
print("---> this is the json object you are sending: \(str)")
}
} catch {
print("---> error: \(error)")
}
where:
func getDiff(old: Lecture, new: Lecture) -> Lecture {
let title = old.title == new.title ? "" : new.title
let color: [String: String] = new.color.filter{ dic in
!old.color.contains(where: { $0.key == dic.key && $0.value == dic.value })
}
let cls = new.class_times.filter{ !old.class_times.contains($0)}
return Lecture(title: title, class_times: cls, color: color)
}
和:
struct ClassTime: Codable, Equatable { // <-- here
let start: Double
let len: Double
}
我認為,您想研究Sets 和 Set Arithmetics 。
這段代碼可能並不完全符合您的要求,但它應該為您指明正確的方向。
通過為兩堂課創建一個對稱的不同時間集,我們得到一個在任一堂課中的時間列表,但不是兩者。
struct Lecture: Codable, Equatable {
let title: String
let times: [LectureTime]
let color: [String: String]
}
struct LectureTime: Codable, Hashable {
let start: Double
let len: Double
}
var oldLecture = Lecture(title: "lecture1",
times: [.init(start: 1, len: 2), .init(start: 5, len: 2)],
color: ["fg": "#fff", "bg": "#000"])
var newLecture = Lecture(title: "lecture1",
times: [.init(start: 2, len: 3), .init(start: 5, len: 2)],
color: ["fg": "#fff", "bg": "#000"])
if oldLecture != newLecture {
let oldTimes = Set(oldLecture.times)
let newTimes = Set(newLecture.times)
let x = oldTimes.symmetricDifference(newTimes)
print(String(describing:x))
}
印刷
[LectureTime(start: 1.0, len: 2.0), LectureTime(start: 2.0, len: 3.0)]
可能您希望擴展您的時間模型以使其可識別——而不是您可以識別的時間已更改。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.