Recursive diff of two python dictionaries (keys and values)?

One option would be to convert any lists you run into as dictionaries with the index as a key. For example: add this function to the same module def list_to_dict(l): return dict(zip(map(str, range(len(l))), l)) add this code under the 'if type(d2k) == dict' block elif type(d2k) == list: dd(list_to_dict(d1k), list_to_dict(d2k), k) Here is the output with the sample dictionaries you gave in comments: d1 = {"name":"Joe", "Pets":{"name":"spot", "species":"dog"}} >>> d2 = {"name":"Joe", "Pets":{"name":"spot", "species":"cat"}} >>> dd(d1, d2, "base") Changes in base Changes in Pets Changes in 0 species changed in d2 to cat Done with changes in 0 Done with changes in Pets Done with changes in base Note that this will compare index by index, so it will need some modification to work well for list items being added or removed.

One option would be to convert any lists you run into as dictionaries with the index as a key. For example: # add this function to the same module def list_to_dict(l): return dict(zip(map(str, range(len(l))), l)) # add this code under the 'if type(d2k) == dict' block elif type(d2k) == list: dd(list_to_dict(d1k), list_to_dict(d2k), k) Here is the output with the sample dictionaries you gave in comments: >>> d1 = {"name":"Joe", "Pets":{"name":"spot", "species":"dog"}} >>> d2 = {"name":"Joe", "Pets":{"name":"spot", "species":"cat"}} >>> dd(d1, d2, "base") Changes in base Changes in Pets Changes in 0 species changed in d2 to cat Done with changes in 0 Done with changes in Pets Done with changes in base Note that this will compare index by index, so it will need some modification to work well for list items being added or removed.

Consider using hasattr(obj, '__iter__') as you recurse through the object. If an object implements the __iter__ method you know you can iterate over it.

Your function should begin by checking the type of its arguments, write the function so that it can handle lists, dictionaries, ints, and strings. That way you don't have to duplicate anything, you just call recursively. Psuedocode: def compare(d1, d2): if d1 and d2 are dicts compare the keys, pass values to compare if d1 and d2 are lists compare the lists, pass values to compare if d1 and d2 are strings/ints compare them.

Just a thought: You could try an object-oriented approach where you derive your own dictionary class that keeps track of any changes made to it (and reports them). Seems like that might have many advantages over trying to compare two dicts... To show that might be done, here's a reasonably complete and somewhat tested sample implementation: class _Null: pass _Null = _Null() # singleton class trackingdict(dict): """ Subclass of dict which tracks all changes in _changelist attribute. """ def __init__(self, *args, **kwargs): super(trackingdict, self).

__init__(*args, **kwargs) self. Init_changelist() for key in sorted(self.iterkeys()): self. _changelist.

Append(AddKey(key, selfkey)) def init_changelist(self): # additional method self. _changelist = def __setitem__(self, key, value): modtype = ChangeKey if key in self else AddKey super(trackingdict, self). __setitem__(key, value) self.

_changelist. Append(modtype(key, selfkey)) def __delitem__(self, key): super(trackingdict, self). __delitem__(key) self.

_changelist. Append(RemoveKey(key)) def clear(self): deletedkeys = self.keys() super(trackingdict, self).clear() for key in sorted(deletedkeys): self. _changelist.

Append(RemoveKey(key)) def update(self, other=_Null): if other is not _Null: otherdict = dict(other) # convert to dict if necessary changedkeys = set(k for k in otherdict if k in self) super(trackingdict, self). Update(other) for key in sorted(otherdict.iterkeys()): if key in changedkeys: self. _changelist.

Append(ChangeKey(key, otherdictkey)) else: self. _changelist. Append(AddKey(key, otherdictkey)) def setdefault(self, key, default=None): if key not in self: selfkey = default # will append an AddKey to _changelist return selfkey def pop(self, key, default=_Null): if key in self: ret = selfkey # save value self.

__delitem__(key) return ret elif default is not _Null: # default specified return default else: # not there & no default selfkey # raise KeyError def popitem(self): key, value = super(trackingdict, self).popitem() self. _changelist. Append(RemoveKey(key)) # change-tracking record classes class DictMutator(object): def __init__(self, key, value=_Null): self.

Key = key self. Value = value def __repr__(self): return '%s(%r%s)' % (self. __class__.

__name__, self. Key, '' if self. Value is _Null else ': '+repr(self.

Value)) class AddKey(DictMutator): pass class ChangeKey(DictMutator): pass class RemoveKey(DictMutator): pass Note that unlike a simple comparison of the before and after state of a dictionary, this class will tell you about keys which were added and then deleted -- in other words, it keeps a complete history until its _changelist is re-initialized.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions