Skip to content

Instantly share code, notes, and snippets.

@matnogaj
Created March 20, 2017 22:26
Show Gist options
  • Save matnogaj/3f3ffb10d7393a585faac25bf49f1655 to your computer and use it in GitHub Desktop.
Save matnogaj/3f3ffb10d7393a585faac25bf49f1655 to your computer and use it in GitHub Desktop.
Dictionary differences
import UIKit
import CoreData
var dictA: [String : Any] = ["key1": "value1", "key3": "value3", "key4": "notModified",
"key5" : 1, "key6" : 1.0,
"key7": ["a", "b"], "key8": ["a"], "key9": ["a", "b"]]
var dictB: [String : Any] = ["key2": "value2", "key3": "modified", "key4": "notModified",
"key5" : 2, "key6" : 2.0,
"key7": ["a", "c"], "key8": ["a", "b"], "key9": ["a"]]
public extension Dictionary {
public func differences(_ other: Dictionary) -> (inserted: Dictionary, removed: Dictionary, updated: Dictionary) {
var inserted = self.filter { other[$0.key] == nil }
var removed = other.filter { self[$0.key] == nil }
let correctUpdated: [(key: Key, value: Value)] = self.flatMap {
guard let otherValue = other[$0.key] else { return nil }
switch ($0.value, otherValue) {
case (let a as String, let b as String): if a != b { return $0 }
case (let a as Int, let b as Int): if a != b { return $0 }
case (let a as Double, let b as Double): if a != b { return $0 }
case (let a as NSManagedObject, let b as NSManagedObject): if a.objectID != b.objectID { return $0 }
case (let a as Array<Any>, let b as Array<Any>):
let insertedToArray = a.filter({ element in
guard let stringElement = element as? String else { return false }
return !b.contains(where: { otherElement in
guard let otherStringElement = otherElement as? String else { return false }
return stringElement == otherStringElement
})
})
let removedFromArray = b.filter({ element in
guard let stringElement = element as? String else { return false }
return !a.contains(where: { otherElement in
guard let otherStringElement = otherElement as? String else { return false }
return stringElement == otherStringElement
})
})
if !removedFromArray.isEmpty {
removed.append((key: $0.key, value: removedFromArray as! Value))
}
if !insertedToArray.isEmpty {
inserted.append((key: $0.key, value: insertedToArray as! Value))
}
return nil
case (let a as NSSet, let b as NSSet):
let insertedToSet = a.filter({ element in
guard let managedElement = element as? NSManagedObject else { return false }
return !b.contains(where: { otherElement in
guard let otherManagedElement = otherElement as? NSManagedObject else { return false }
return managedElement.objectID == otherManagedElement.objectID
})
})
let removedFromSet = b.filter({ element in
guard let managedElement = element as? NSManagedObject else { return false }
return !a.contains(where: { otherElement in
guard let otherManagedElement = otherElement as? NSManagedObject else { return false }
return managedElement.objectID == otherManagedElement.objectID
})
})
if !removedFromSet.isEmpty {
removed.append((key: $0.key, value: removedFromSet as! Value))
}
if !insertedToSet.isEmpty {
inserted.append((key: $0.key, value: insertedToSet as! Value))
}
return nil
default: return nil
}
return nil
}
var insertedDict: Dictionary = [:]
inserted.forEach { insertedDict[$0.key] = $0.value }
var removedDict: Dictionary = [:]
removed.forEach { removedDict[$0.key] = $0.value }
var updatedDict: Dictionary = [:]
correctUpdated.forEach { updatedDict[$0.key] = $0.value }
return (insertedDict, removedDict, updatedDict)
}
}
let (inserted, removed, updated) = dictB.differences(dictA)
print("inserted: \(inserted)")
print("removed: \(removed)")
print("updated: \(updated)")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment