2013-03-15 158 views
3

我需要递归地遍历字典,并且记得以前的键递归遍历字典

让我解释一下:

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

元素始终是一个值或一本字典,直到它达到的值。 我想打印上述dic这样的:(忽略以下XXX,它最终应该是两个值的差异)

resources info load 37 17 xxx 
resources peak load 0 1 xxx 

这是我的代码至今:

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) 

我不知道如何递送先前的键递归到该函数!要么我得到一个额外的打印键或什么都没有! (请不要指教我,我应该使用json.dumps,因为它并没有真正做我需要的!) 我希望有人可以检查我的解决方案并指出其中的缺陷!

+0

的孩子可以是类型列表或字典? – Fabian 2013-03-15 15:53:58

+0

键'level1'具有类型dict的值,但'level2B'和'level3B'具有值为dicts的列表。 Can/should'level1'是一个包含单个字典的列表吗? – Awalias 2013-03-15 15:55:01

+0

@fabian,对不起,我搞砸了这个例子。孩子总是一个元素或一个元组 – theAlse 2013-03-15 15:57:25

回答

5

我不知道什么是你的代码错误,但是这可能会做你想要什么:

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遍历传入的字典,并返回一个(path, value)元组。 path本身就是一个元组,它描述了到达该项目的键。

上面的代码打印:

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

如果你想打印这个表,更换了循环以上这样的:

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 

它打印:

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

我希望有人能指出我的解决方案中的缺陷。我不知道如何改变这些代码来获得价值的差异。 – theAlse 2013-03-15 16:34:28

+0

啊,我误解了你的问题,因为*你没有问过*。你可能想编辑你的文章并包含一个特定的问题。 – 2013-03-15 16:36:26

+0

完成了,你的代码比我的代码简单得多:) – theAlse 2013-03-15 16:38:04

2
def convertToTable(inp, history=[]): 
    for key, value in inp.iteritems(): 
     history.append(key) 
     if type(value) == dict: 
      convertToTable(value, history) 
     else: 
      print '{} {} {}'.format(' -> '.join(history), value[0], value[1]) 
     history.pop() 

dic = {'peak': {'load': ('0', '1'), 'unload': ('2', '3')}, 'resources': {'info': {'loadxx': ('37', '17')}}} 
convertToTable(dic) 

# peak -> load 0 1 
# peak -> unload 2 3 
# resources -> info -> loadxx 37 17 
2

我有两个解决方案,第一辆车将所有按键的名称向下输出,并在返回堆栈之前将其打印在底部。

第二打印他们一路下滑从而避免了必须“记住”水平

import sys 

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


def racecar(goomba, levels=None): 
    if levels == None: 
     levels = [] 
    for key in goomba: 
     if type(goomba[key]) is dict: 
      levels.append(key) 
      levels = racecar(goomba[key], levels) 
     else: 
      levels.append(key) 
      for name in levels: 
       sys.stdout.write(name + ' ') 
      for val in goomba[key]: 
       sys.stdout.write(val + ' ') 
      sys.stdout.write('xxx\n') 
      return [] 


def racecar2(goomba): 
    for key in goomba: 
     sys.stdout.write(key + ' ') 
     if type(goomba[key]) is dict: 
      racecar(goomba[key]) 
     else: 
      for val in goomba[key]: 
       sys.stdout.write(val + ' ') 
      sys.stdout.write('xxx\n') 

racecar(dic) 
racecar2(dic) 

回报:

peak load 0 1 xxx 
resources info load 37 17 xxx 
+0

感谢您的回复,您的解决方案都不正确!几乎和我的方式不一样。你运行了他们并检查了印刷品,它甚至没有印刷所有的元素! – theAlse 2013-03-15 16:33:16

+0

在您的问题中指定的输出似乎并不反映提供的输入。你期待什么输出? – Awalias 2013-03-15 16:36:10

+0

oops我错过了'load'元素,现在修复了 – Awalias 2013-03-15 16:39:44