【问题标题】:Traversing a dictionary recursively递归遍历字典
【发布时间】:2013-03-04 09:33:50
【问题描述】:

我需要递归遍历字典并记住之前的键

让我解释一下:

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,因为它并不能真正满足我的需要!) 我希望有人可以检查我的解决方案并指出其中的缺陷!

【问题讨论】:

  • 子元素可以是类型列表还是字典?
  • key level1 的值是 dict 类型,但 level2Blevel3B 的值是 dicts 列表。 level1 可以/应该是一个包含单个字典的列表吗?
  • @fabian,对不起,我搞砸了这个例子。孩子总是一个元素或元组
  • @theAlse 什么是元素?你能更新你的帖子吗?
  • 对不起,我搞砸了这个例子。请看更新的!

标签: python recursion dictionary python-2.7


【解决方案1】:

我不确定您的代码有什么问题,但这可能会满足您的需求:

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 循环替换为:

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

【讨论】:

  • 我希望有人能指出我的解决方案中的缺陷。我不知道如何更改此代码以获取值的差异。
  • 啊,我误解了你的问题,因为你没有问过。您可能想要编辑您的帖子并包含一个特定问题。
  • 什么是“价值差异”?根据您的示例输入,您希望输出看起来像什么?
  • 我的意思是为每个项目提供的两个值之间的差异,但这也很容易从您的代码中得到
  • 我接受你的解决方案,因为它是最简单易懂的
【解决方案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

【讨论】:

    【解决方案3】:

    我有两个解决方案,第一个将所有键的名称向下传递并打印在底部,然后返回堆栈。

    第二个在下降过程中打印它们,从而避免必须“记住”级别

    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
    

    【讨论】:

    • 感谢您的回复,您的两个解决方案都不正确!几乎以同样的方式我的不正确。你有没有运行它们并检查过打印,它甚至没有打印所有元素!
    • 您的问题中指定的输出似乎并未反映所提供的输入。你期待什么输出?
    • 哎呀我错过了 load 元素,现在已修复
    猜你喜欢
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    • 2011-04-21
    • 2014-07-19
    • 2018-12-02
    • 1970-01-01
    • 2017-09-03
    • 2018-07-12
    相关资源
    最近更新 更多