簡體   English   中英

如何遞歸比較兩個 Codable 對象並在 Swift 中獲得差異?

[英]How to recursively compare two Codable objects and get differences in Swift?

我有兩個Lecture實例,它們是oldLecturenewLecture Lecture的簡化聲明如下(完整版有更多字段):

struct Lecture: Codable {
    let title: String
    let class_times: [ClassTime]
    let color: [String: String]
}

struct ClassTime: Codable {
    let start: Double
    let len: Double
}

現在我需要遞歸地比較oldLecturenewLecture ,並創建一個新的類字典對象,該對象包含在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
    }
}

上面的方法不起作用,因為它不會遞歸地比較oldValnewVal

有沒有更簡潔的方法來實現這一點,而不使用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字段中具有標題差異,對於colorclass_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM