Traversing a dictionary recursively

dictionary, python, python-2.7, recursion

Solution

I'm not sure what's wrong with your code, but this might do what you want:

def iteritems_recursive(d):
  for k,v in d.iteritems():
    if isinstance(v, dict):
      for k1,v1 in iteritems_recursive(v):
        yield (k,)+k1, v1
    else:
      yield (k,),v

dic = {u'resources': {u'info': {u'load': (u'37', u'17')}, u'peak': {u'load': (u'0', u'1')}}}

for p,v in iteritems_recursive(dic):
  print p, "->", v

`iteritems_recursive` iterates over the passed-in dictionary, and returns a a `(path, value)` tuple. The `path` is itself a tuple which describes the keys that reach that item.

The above code prints:

(u'resources', u'info', u'load') -> (u'37', u'17')
(u'resources', u'peak', u'load') -> (u'0', u'1')

If you want to print the table pretty, replace the for loop above with this:

for p,v in iteritems_recursive(dic):
  diff = float(v[0]) - float(v[1])
  p = ''.join('{:10}'.format(w) for w in p)
  v = ''.join('{:5}'.format(f) for f in v)
  print p, v, diff

Which prints:

resources info      load       37   17    20.0
resources peak      load       0    1     -1.0

Problem

I need to traverse a dictionary recursively and remember the previous keys. Let me explain: ``` dic = {u'resources': {u'info': {u'load': (u'37', u'17')}}, u'peak': {u'load': (u'0', u'1')}} ``` The elements are always a value or a dictionary until it reaches a value. I want to print the above `dic` like this: (omit the xxx below, it should eventually be a diff of the two values) ``` resources info load 37 17 xxx resources peak load 0 1 xxx ``` This is the code I have so far: ``` def convertToTable(var): if isinstance(var, tuple): if len(var) != 2: return str(var) v1, v2 = var try: v1 = float(v1) v2 = float(v2) except ValueError: pass if type(v1) != type(v2): return '\t%s\t%s\n' % (v1, v2) elif isinstance(v1, int) or isinstance(v1, float): sign = '+' if v2 - v1 > 0 else '' return '\t%s\t%s\t%s%s\n' % (v1, v2, sign, v2 - v1) elif isinstance(v1, list): ret = '' for i in range(max(len(v1), len(v2))): v1v = v1[i] if i < len(v1) else '' v2v = v2[i] if i < len(v2) else '' ret += '\t%s, %s\n' % (v1v, v2v) return ret else: return '\t%s\t%s\n' % (v1, v2) elif isinstance(var, dict): ret = '' for key, value in var.iteritems(): # fix this crap, it's not printing all recursive levels of keys! ret += '%s %s' % (key, convertToTable(value)) return ret else: return '%s\n' % (var) ``` I don´t know how to pass the previous keys recursively to the function again! Either I get an extra print of keys or nothing! (please do not advice me that I should use `json.dumps` as it does not really do what I need!) I am hoping someone can check my solution and point out the flaw in it!

Original source