dict diff
so i came up with a diff method to compare 2 dicts. i found it pretty useful so i thought i'd share it with everyone. you can see the doctest to check out suggested uses. since we can't modify built-ins, i demonstrated adding a diff method to OrderedDict to show how one could add it to your own mapping objects. the core logic is compatible with python2 and 3 (i've only tested using 2.6.5 and 3.1.2). the doctest is suited for python3 though. the interface is pretty straightforward. it would be awesome to have this sucker as a method on the builtin dict, but that'd take a pep, no? -- Jin Yi __author__ = 'razamatan_retral_net_ignore_com' from collections import Mapping def diffdict(left, right): ''' returns the deep diff of two dicts. the return value the tuple (left_diff, right_diff) >>> diffdict(1, None) (1, None) >>> diffdict({1:2}, None) ({1: 2}, None) >>> diffdict({1:2}, {3:4}) ({1: 2, 3: }, {1: , 3: 4}) >>> from collections import OrderedDict >>> x = OrderedDict({1:2, 3:{4:{5:[6,7], 8:9}}}) >>> diffdict(x, x) (None, None) >>> y = {1:2, 3:[4]} >>> diffdict(x, y) ({3: {4: {8: 9, 5: [6, 7]}}}, {3: [4]}) >>> y = {1:2, 3:{4:{5:[6,7]}}} >>> diffdict(x, y) ({3: {4: {8: 9}}}, {3: {4: {8: }}}) >>> y = {1:2, 3:{4:{5:{6:7}, 8:9}}} >>> diffdict(x, y) ({3: {4: {5: [6, 7]}}}, {3: {4: {5: {6: 7) >>> del y[3] >>> diffdict(x, y) ({3: {4: {8: 9, 5: [6, 7]}}}, {3: }) >>> y = {1:2, 3:{4:{5:[6,10], 8:9}}} >>> diffdict(x, y) ({3: {4: {5: [6, 7]}}}, {3: {4: {5: [6, 10]}}}) >>> y = {1:100, 3:{4:{5:[6,7], 8:9}}} >>> diffdict(x, y) ({1: 2}, {1: 100}) >>> diffdict(y, x) ({1: 100}, {1: 2}) >>> x.__class__.diff = diffdict >>> x.__class__.__xor__ = diffdict >>> x.diff(x) (None, None) >>> x ^ y ({1: 2}, {1: 100}) ''' # base case if not isinstance(left, Mapping) or not isinstance(right, Mapping): return (left, right) # key exclusivity left_diff = dict(i for i in left.items() if i[0] not in right) right_diff = dict(i for i in right.items() if i[0] not in left) right_diff.update((k, KeyError) for k in left_diff if k not in right_diff) left_diff.update((k, KeyError) for k in right_diff if k not in left_diff) # value differences for k in (k for k in left if k in right): if left[k] != right[k]: (ld, rd) = diffdict(left[k], right[k]) left_diff[k] = ld or None right_diff[k] = rd or None left_diff = left_diff or None right_diff = right_diff or None return (left_diff, right_diff) -- http://mail.python.org/mailman/listinfo/python-list
Re: dict diff
i don't think this piece of code is obscure. i think the use case is there when you know that dicta != dictb, but you need to know where they're different. i wouldn't really care to have it on the dict since it's useful as an unbound method anyway. On Sat, Nov 20, 2010 at 01:11:53AM -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. i found it pretty > > useful so i thought i'd share it with everyone. you can see the doctest > > to check out suggested uses. since we can't modify built-ins, i > > demonstrated adding a diff method to OrderedDict to show how one could > > add it to your own mapping objects. > > > > the core logic is compatible with python2 and 3 (i've only tested using > > 2.6.5 and 3.1.2). the doctest is suited for python3 though. > > > > > > the interface is pretty straightforward. it would be awesome to have > > this sucker as a method on the builtin dict, but that'd take a pep, no? > > > > > > > A PEP *and* some explanation of why you would want such an obscure piece > of code built in to the dict object, yes. > > regards > Steve > -- > Steve Holden +1 571 484 6266 +1 800 494 3119 > PyCon 2011 Atlanta March 9-17 http://us.pycon.org/ > See Python Video! http://python.mirocommunity.org/ > Holden Web LLC http://www.holdenweb.com/ > > -- > http://mail.python.org/mailman/listinfo/python-list -- http://mail.python.org/mailman/listinfo/python-list
Re: dict diff
right. i moved to a 2-value tuple return value basically to illustrate exactly where each dict is providing a different value. it turns out to be much easier to grok than the 3-value one since it's all there and lines up correctly with the inputs... On Sat, Nov 20, 2010 at 12:00:16PM +, Steven D'Aprano 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) > > > -- > Steven > -- > http://mail.python.org/mailman/listinfo/python-list -- I pops mah collah. (Busta Rhymes) Jin Yi -- http://www.retral.net/razamatan -- http://mail.python.org/mailman/listinfo/python-list