How to Combine Two Dictionary Instances in Swift

How can I combine two Dictionary instances in Swift?

var d1 = ["a": "b"]
var d2 = ["c": "e"]

extension Dictionary {
mutating func merge(dict: [Key: Value]){
for (k, v) in dict {
updateValue(v, forKey: k)
}
}
}

d1.merge(d2)

Refer to the awesome Dollar & Cent project
https://github.com/ankurp/Cent/blob/master/Sources/Dictionary.swift

How do you add a Dictionary of items into another Dictionary

You can define += operator for Dictionary, e.g.,

func += <K, V> (left: inout [K:V], right: [K:V]) { 
for (k, v) in right {
left[k] = v
}
}

How to add another dictionary entry to an existing dictionary to form a new dictionary (i.e. not append)

There is a built-in merging(_:uniquingKeysWith:) function on Dictionary that does exactly what you need.

let dictionary = [1:1]
let otherDictionary = [1:2, 2:3]
// This will take the values from `otherDictionary` if the same key exists in both
// You can use `$0` if you want to take the value from `dictionary` instead
let mergedDict = dictionary.merging(otherDictionary, uniquingKeysWith: { $1 })

If you want, you can easily define a + operator for Dictionary that uses the above function.

extension Dictionary {
static func + (lhs: Self, rhs: Self) -> Self {
lhs.merging(rhs, uniquingKeysWith: { $1 })
}
}

let addedDict = dictionary + otherDictionary

How do I write a generic Swift extension to deep merge two dictionaries?

Note that the error is on the assignment to result[key], not on the function call itself:

let merged: [Key:Value] = existing.deepMerged(with: value)  //works fine
result[key] = merged //error

The compiler knows that:

  • result is a [Key: Value]
  • other is a [Key: Value]
  • key is a Key
  • value is a Value
  • merged is a [Key:Value]
  • result has a subscript(key: Key) -> Value? { get set } (i.e. a writable subscript of type Value? which accepts a Key)

But it does not know that [Key:Value] is a Value, so it does not know that merged can be passed to the subscript of result. Since value is a Value and value is also [Key: Value], we know that [Key: Value] must be a Value, but the compiler does not know that.

A solution is to cast merged to a Value:

extension Dictionary {
public func deepMerged(with other: [Key: Value]) -> [Key: Value]
{
var result: [Key: Value] = self
for (key, value) in other {
if let value = value as? [Key: Value],
let existing = result[key] as? [Key: Value],
let merged = existing.deepMerged(with: value) as? Value
{
result[key] = merged
} else {
result[key] = value
}
}
return result
}
}

Merging Dictionaries with multiple Types, or Any / AnyObject Type

You don't actually need to (and you can't) specify the Any type in the function declaration - you need to have the subtypes of the newValues dictionary match the dictionary it's extending:

extension Dictionary {
mutating func extend(newVals: Dictionary) {
for (key,value) in newVals {
self.updateValue(value, forKey:key)
}
}
}

var dict = ["one": 1, "two": 2, "hello": "goodbye"]
dict.extend(["three": 3])
dict.extend(["foo": "bar"])

Key and Value are type aliases within the Dictionary type that map to the specific key- and value-types of a particular instance.

Comparing two [String: Any] dictionaries in Swift 4

Details

  • Xcode Version 10.3 (10G8), Swift 5

Solution

func areEqual (_ left: Any, _ right: Any) -> Bool {
if type(of: left) == type(of: right) &&
String(describing: left) == String(describing: right) { return true }
if let left = left as? [Any], let right = right as? [Any] { return left == right }
if let left = left as? [AnyHashable: Any], let right = right as? [AnyHashable: Any] { return left == right }
return false
}

extension Array where Element: Any {
static func != (left: [Element], right: [Element]) -> Bool { return !(left == right) }
static func == (left: [Element], right: [Element]) -> Bool {
if left.count != right.count { return false }
var right = right
loop: for leftValue in left {
for (rightIndex, rightValue) in right.enumerated() where areEqual(leftValue, rightValue) {
right.remove(at: rightIndex)
continue loop
}
return false
}
return true
}
}
extension Dictionary where Value: Any {
static func != (left: [Key : Value], right: [Key : Value]) -> Bool { return !(left == right) }
static func == (left: [Key : Value], right: [Key : Value]) -> Bool {
if left.count != right.count { return false }
for element in left {
guard let rightValue = right[element.key],
areEqual(rightValue, element.value) else { return false }
}
return true
}
}

Usage

let comparisonResult = ["key1": 1, 2: "Value2"] == ["key1": ["key2":2]]     // false
print("!!!! \(comparisonResult)")

Some tests

func test(dict1: [AnyHashable : Any], dict2:  [AnyHashable : Any]) {
print("========================")
print("dict1: \(dict1)")
print("dict2: \(dict2)")
print("are\(dict1 == dict2 ? " " : " not ")equal")
}

test(dict1: ["key1": 1, 2: "Value2"],
dict2: ["key1": 1, 2: "Value2"])

test(dict1: ["key1": 1, 2: "Value2"],
dict2: ["key1": 1])

test(dict1: [2: "Value2"],
dict2: ["key1": 1])

test(dict1: ["1": 1],
dict2: [1: 1])

test(dict1: [1: 2],
dict2: [1: 3])

test(dict1: ["key1": [1,2,3,4]],
dict2: ["key1": [1,2,3,4]])

test(dict1: ["key1": [1,2,3,4]],
dict2: ["key1": [2,1,3,4]])

test(dict1: ["key1": [1,2,3,4]],
dict2: ["key1": [2,1,3]])

test(dict1: ["key1": [1,2,3,4]],
dict2: ["key1": [1,2,3,"4"]])

test(dict1: ["key1": ["key2":2]],
dict2: ["key1": ["key2":2]])

test(dict1: ["key1": ["key2":2]],
dict2: ["key1": ["key2":3]])

test(dict1: ["key1": ["key2":2]],
dict2: ["key1": ["key2":3]])

Tests results

========================
dict1: [AnyHashable("key1"): 1, AnyHashable(2): "Value2"]
dict2: [AnyHashable("key1"): 1, AnyHashable(2): "Value2"]
are equal
========================
dict1: [AnyHashable("key1"): 1, AnyHashable(2): "Value2"]
dict2: [AnyHashable("key1"): 1]
are not equal
========================
dict1: [AnyHashable(2): "Value2"]
dict2: [AnyHashable("key1"): 1]
are not equal
========================
dict1: [AnyHashable("1"): 1]
dict2: [AnyHashable(1): 1]
are not equal
========================
dict1: [AnyHashable(1): 2]
dict2: [AnyHashable(1): 3]
are not equal
========================
dict1: [AnyHashable("key1"): [1, 2, 3, 4]]
dict2: [AnyHashable("key1"): [1, 2, 3, 4]]
are equal
========================
dict1: [AnyHashable("key1"): [1, 2, 3, 4]]
dict2: [AnyHashable("key1"): [2, 1, 3, 4]]
are equal
========================
dict1: [AnyHashable("key1"): [1, 2, 3, 4]]
dict2: [AnyHashable("key1"): [2, 1, 3]]
are not equal
========================
dict1: [AnyHashable("key1"): [1, 2, 3, 4]]
dict2: [AnyHashable("key1"): [1, 2, 3, "4"]]
are not equal
========================
dict1: [AnyHashable("key1"): ["key2": 2]]
dict2: [AnyHashable("key1"): ["key2": 2]]
are equal
========================
dict1: [AnyHashable("key1"): ["key2": 2]]
dict2: [AnyHashable("key1"): ["key2": 3]]
are not equal
========================
dict1: [AnyHashable("key1"): ["key2": 2]]
dict2: [AnyHashable("key1"): ["key2": 3]]
are not equal


Related Topics



Leave a reply



Submit