Moje potrzeby były różne, chciałem się połączyć, a nie obijać.
merging:
["b": [1, 2], "s": Set([5, 6]), "a": 1, "d": ["x": 2]]
with
["b": [3, 4], "s": Set([6, 7]), "a": 2, "d": ["y": 4]]
yields:
["b": [1, 2, 3, 4], "s": Set([5, 6, 7]), "a": 2, "d": ["y": 4, "x": 2]]
Miałem nadzieję na prostsze rozwiązanie, ale to właśnie udało mi się uzyskać. Wyzwanie polegało na przechodzeniu od dynamicznego pisania do pisania statycznego, a ja użyłem protokołów, aby rozwiązać ten problem.
Warto również zauważyć, że przy użyciu składni literału słownikowego otrzymuje się typy fundamentów, które nie przechwytują rozszerzeń protokołu. Przerwałem moje wysiłki, by wspierać tych, ponieważ nie mogłem łatwo zweryfikować jednolitości elementów kolekcji.
import UIKit
private protocol Mergable {
func mergeWithSame<T>(right: T) -> T?
}
public extension Dictionary {
/**
Merge Dictionaries
- Parameter left: Dictionary to update
- Parameter right: Source dictionary with values to be merged
- Returns: Merged dictionay
*/
func merge(right:Dictionary) -> Dictionary {
var merged = self
for (k, rv) in right {
// case of existing left value
if let lv = self[k] {
if let lv = lv as? Mergable where lv.dynamicType == rv.dynamicType {
let m = lv.mergeWithSame(rv)
merged[k] = m
}
else if lv is Mergable {
assert(false, "Expected common type for matching keys!")
}
else if !(lv is Mergable), let _ = lv as? NSArray {
assert(false, "Dictionary literals use incompatible Foundation Types")
}
else if !(lv is Mergable), let _ = lv as? NSDictionary {
assert(false, "Dictionary literals use incompatible Foundation Types")
}
else {
merged[k] = rv
}
}
// case of no existing value
else {
merged[k] = rv
}
}
return merged
}
}
extension Array: Mergable {
func mergeWithSame<T>(right: T) -> T? {
if let right = right as? Array {
return (self + right) as? T
}
assert(false)
return nil
}
}
extension Dictionary: Mergable {
func mergeWithSame<T>(right: T) -> T? {
if let right = right as? Dictionary {
return self.merge(right) as? T
}
assert(false)
return nil
}
}
extension Set: Mergable {
func mergeWithSame<T>(right: T) -> T? {
if let right = right as? Set {
return self.union(right) as? T
}
assert(false)
return nil
}
}
var dsa12 = Dictionary<String, Any>()
dsa12["a"] = 1
dsa12["b"] = [1, 2]
dsa12["s"] = Set([5, 6])
dsa12["d"] = ["c":5, "x": 2]
var dsa34 = Dictionary<String, Any>()
dsa34["a"] = 2
dsa34["b"] = [3, 4]
dsa34["s"] = Set([6, 7])
dsa34["d"] = ["c":-5, "y": 4]
//let dsa2 = ["a": 1, "b":a34]
let mdsa3 = dsa12.merge(dsa34)
print("merging:\n\t\(dsa12)\nwith\n\t\(dsa34) \nyields: \n\t\(mdsa3)")
także oba dicts są stałymi (niech) to oczywiście nie można zmienić dict1 ... –
Ta odpowiedź (https://stackoverflow.com/a/46542912/2020034) powinna pomóc –