Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to extract differences between dictionaries?

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?

like image 633
TruMan1 Avatar asked Aug 09 '16 23:08

TruMan1


People also ask

How do you find the difference between two dictionaries?

With set. Here we take two dictionaries and apply set function to them. Then we subtract the two sets to get the difference. We do it both ways, by subtracting second dictionary from first and next subtracting first dictionary form second.

How do I compare two dictionaries in Python?

Using == operator to Compare Two Dictionaries Here we are using the equality comparison operator in Python to compare two dictionaries whether both have the same key value pairs or not.

How do I tell if two dictionaries are identical in Python?

Use == to check equality of two dictionaries Use == to check if two dictionaries contain the same set of key: value pairs.


1 Answers

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

Value must be Equatable

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.

The code

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.

Examples

["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

The != operator

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

Shorter version

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] }
}

Update

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]
like image 190
Luca Angeletti Avatar answered Sep 28 '22 16:09

Luca Angeletti