TruMan1 - 1 year ago 72

Swift Question

I can compare whether 2 dictionaries match or not like this:

`func ==(lhs: [String: AnyObject], rhs: [String: AnyObject] ) -> Bool {`

return NSDictionary(dictionary: lhs).isEqualToDictionary(rhs)

}

Is there a concise way to extract the differences between 2 dictionaries, as in the opposite of the intersection?

Answer Source

We can define an operator to check whether 2 dictionaries contains the same keys and for each key the same value.

First of all we need to use generics to require that the `Value`

of the dictionaries conforms to `Equatable`

otherwise we won't be able to compare the values.

Here's the code

```
func ==<Value:Equatable>(left: [String: Value], right: [String: Value]) -> Bool {
guard left.keys.count == right.keys.count else { return false }
let differenceFound = zip(left.keys.sort(), right.keys.sort()).contains { elm -> Bool in
let leftKey = elm.0
let rightKey = elm.1
return leftKey != rightKey || left[leftKey] != right[rightKey]
}
return !differenceFound
}
```

The first line verify that the dictionaries have the same number of entries, otherwise `false`

is returned.

The next block of code sort the keys of both dictionaries and compare each pair looking for a pair where the keys or the values are different.

If such difference is not found then the dictionaries have the same keys and values, so they are equals.

```
["a":1, "b": 2] == ["a":1, "b": 2] // true
```

Of course since values inside a dictionaries don't have an order the following is still true

```
["a":1, "b": 2] == ["b":2, "a": 1] // true
```

In the next example we compare 2 dictionaries with a different number of values

```
["a":1, "b": 2] == ["a":1, "b": 2, "c": 3] // false
```

Since we defined the `==`

operator, Swift gifts us the `!=`

operator (which simply returns the opposite of `==`

), so we can also write

```
["a":1, "b": 2] != ["d":4] // true
```

The same operator can also be written in this shorter way

```
func ==<Value:Equatable>(left: [String: Value], right: [String: Value]) -> Bool {
return
left.keys.count == right.keys.count &&
!zip(left.keys.sort(), right.keys.sort()).contains { $0 != $1 || left[$0] != right[$1] }
}
```

Now given 2 dictionaries `a`

and `b`

, you want to perform `a.minus(b)`

and get as result a new dictionaries containing all the `(key, value)`

pairs available in `a`

and not available in `b`

.

Here's the code

```
extension Dictionary where Key: Comparable, Value: Equatable {
func minus(dict: [Key:Value]) -> [Key:Value] {
let entriesInSelfAndNotInDict = filter { dict[$0.0] != self[$0.0] }
return entriesInSelfAndNotInDict.reduce([Key:Value]()) { (res, entry) -> [Key:Value] in
var res = res
res[entry.0] = entry.1
return res
}
}
}
```

Examples

```
["a":1].minus(["a":2]) // ["a": 1]
["a":1].minus(["a":1]) // [:]
["a":1].minus(["a":1, "b":2]) // [:]
["a":1, "b": 2].minus(["a":1]) // ["b": 2]
```