dict diff

geremy condra debatem1 at gmail.com
Sat Nov 20 18:14:59 EST 2010


On Sat, Nov 20, 2010 at 4:00 AM, Steven D'Aprano
<steve at remove-this-cybersource.com.au> wrote:
> On Sat, 20 Nov 2010 01:11:53 -0500, Steve Holden wrote:
>
>> On 11/19/2010 8:58 PM, Jin Yi wrote:
>>> so i came up with a diff method to compare 2 dicts.
> [...]
>> A PEP *and* some explanation of why you would want such an obscure piece
>> of code built in to the dict object, yes.
>
> You've never wanted to see how two dicts differ, as well as the fact that
> they do? I frequently find myself wanting to see why two dicts that
> should be equal aren't, especially for testing and debugging.
>
> I use this function:
>
> def dict_diffs(a, b):
>    """dict_diffs(adict, bdict) -> (amissing, bmissing, different)
>
>    Returns sets (amissing, bmissing, different) such that:
>
>    amissing = keys missing from adict compared to bdict
>    bmissing = keys missing from bdict compared to adict
>    different = keys in both adict and bdict but with different values
>
>    >>> dict_diffs({1:0, 2:0, 3:0}, {1:1, 2:0, 4:0})
>    (set([4]), set([3]), set([1]))
>
>    """
>    from collections import Mapping
>    if not isinstance(a, Mapping) and isinstance(b, Mapping):
>        raise TypeError('arguments must both be mappings')
>    amissing, bmissing, different = set(), set(), set()
>    for key, value in a.items():
>        if key not in b:
>            bmissing.add(key)
>        elif value != b[key]:
>            different.add(key)
>    for key, value in b.items():
>        if key not in a:
>            amissing.add(key)
>    return (amissing, bmissing, different)

Add me to this group. I frequently use some homebrew set operations on
dictionaries. My (stupid) implementation:

#! /usr/bin/env python3

class AugmentedDict(dict):

    def __and__(self, other):
        """Dictionary intersection operation"""
        return AugmentedDict(self.items() & other.items())

    def __or__(self, other):
        """Dictionary union operation"""
        union = self.items() | other.items()
        merged_union = AugmentedDict(union)
        if len(union) != len(merged_union):
            err = 'Cannot take union of non-pairwise disjoint dictionaries'
            raise Exception(err)
        return merged_union

    def __sub__(self, other):
        """Dictionary difference operation"""
        return AugmentedDict(self.items() - other.items())

    def __xor__(self, other):
        """Dictionary symmetric difference operation"""
        return AugmentedDict(self.items() ^ other.items())

if __name__ == "__main__":

    # demonstrate the behavior of AugmentedDict
    a = AugmentedDict({'a': 1, 'b': 2, 'c': 3})
    b = AugmentedDict({'b': 2, 'c': 3})
    c = AugmentedDict({'a': 1})
    assert( (a|(b|c)) == (b|(a|c)))
    assert( (a&(b&c)) == (b&(a&c)))
    assert( (b&c) == (c&b))
    assert( (a - b) == c)
    assert( (a ^ b) == ((a-b) | (b-a)))


Truth be told, I was under the impression that this was actually going
to be a part of dictionary behavior at some point, maybe I was
thinking of the .items() behavior.

Geremy Condra



More information about the Python-list mailing list