循环遍历所有嵌套的字典值?

2024-04-25 15:05:53 发布

您现在位置:Python中文网/ 问答频道 /正文

for k, v in d.iteritems():
    if type(v) is dict:
        for t, c in v.iteritems():
            print "{0} : {1}".format(t, c)

我试图遍历一个字典并打印出所有键值对,其中的值不是嵌套字典。如果值是一个字典,我想进入它并打印出它的键值对…等等。有什么帮助吗?

编辑

这个怎么样?它仍然只印了一件事。

def printDict(d):
    for k, v in d.iteritems():
        if type(v) is dict:
            printDict(v)
        else:
            print "{0} : {1}".format(k, v)

完整测试用例

字典:

{u'xml': {u'config': {u'portstatus': {u'status': u'good'}, u'target': u'1'},
      u'port': u'11'}}

结果:

xml : {u'config': {u'portstatus': {u'status': u'good'}, u'target': u'1'}, u'port': u'11'}

Tags: inconfigformatforif字典istype
3条回答

由于dict是可接受的,因此您只需稍作更改就可以将经典的nested container iterable formula应用于此问题。下面是Python2版本(请参见下面的3部分):

import collections
def nested_dict_iter(nested):
    for key, value in nested.iteritems():
        if isinstance(value, collections.Mapping):
            for inner_key, inner_value in nested_dict_iter(value):
                yield inner_key, inner_value
        else:
            yield key, value

测试:

list(nested_dict_iter({'a':{'b':{'c':1, 'd':2}, 
                            'e':{'f':3, 'g':4}}, 
                       'h':{'i':5, 'j':6}}))
# output: [('g', 4), ('f', 3), ('c', 1), ('d', 2), ('i', 5), ('j', 6)]

在Python 2中,它可能会创建一个自定义的Mapping,该自定义的Mapping符合Mapping的条件,但不包含iteritems,在这种情况下,这将失败。文档并不表示Mapping需要iteritems;另一方面,source给出Mapping类型的iteritems方法。所以对于自定义的Mappings,显式继承collections.Mapping,以防万一。

在Python 3中,有许多改进要做。从Python 3.3开始,抽象基类就存在于collections.abc中。为了向后兼容,它们也保留在collections中,但是最好将抽象基类放在一个名称空间中。所以这从collections导入abc。Python 3.3还添加了yield from,这是专为这类情况而设计的。这不是空的语法糖;它可能导致faster code和与coroutines的更合理的交互。

from collections import abc
def nested_dict_iter(nested):
    for key, value in nested.items():
        if isinstance(value, abc.Mapping):
            yield from nested_dict_iter(value)
        else:
            yield key, value

如果您使用stack编写自己的递归实现或等价的迭代实现,则存在潜在的问题。请参见以下示例:

    dic = {}
    dic["key1"] = {}
    dic["key1"]["key1.1"] = "value1"
    dic["key2"]  = {}
    dic["key2"]["key2.1"] = "value2"
    dic["key2"]["key2.2"] = dic["key1"]
    dic["key2"]["key2.3"] = dic

在正常意义上,嵌套字典将是一个n元树状数据结构。但定义并没有排除交叉边甚至后边缘(因此不再是树)的可能性。例如,这里key2.2key1保存到字典,key2.3指向整个字典(back edge/cycle)。当存在后边(循环)时,堆栈/递归将无限运行。

                          root<-------back edge
                        /      \           |
                     _key1   __key2__      |
                    /       /   \    \     |
               |->key1.1 key2.1 key2.2 key2.3
               |   /       |      |
               | value1  value2   |
               |                  | 
              cross edge----------|

如果您使用此实现从Scharron打印此词典

    def myprint(d):
      for k, v in d.items():
        if isinstance(v, dict):
          myprint(v)
        else:
          print "{0} : {1}".format(k, v)

您将看到以下错误:

    RuntimeError: maximum recursion depth exceeded while calling a Python object

senderle实现也是如此。

类似地,您可以从Fred Foo中获得这个实现的无限循环:

    def myprint(d):
        stack = list(d.items())
        while stack:
            k, v = stack.pop()
            if isinstance(v, dict):
                stack.extend(v.items())
            else:
                print("%s: %s" % (k, v))

但是,Python实际上在嵌套字典中检测循环:

    print dic
    {'key2': {'key2.1': 'value2', 'key2.3': {...}, 
       'key2.2': {'key1.1': 'value1'}}, 'key1': {'key1.1': 'value1'}}

“{…}”是检测循环的位置。

根据Moondra的要求,这是避免循环(DFS)的一种方法:

def myprint(d): 
  stack = list(d.items()) 
  visited = set() 
  while stack: 
    k, v = stack.pop() 
    if isinstance(v, dict): 
      if k not in visited: 
        stack.extend(v.items()) 
      else: 
        print("%s: %s" % (k, v)) 
      visited.add(k)

正如Niklas所说,你需要递归,即你想定义一个函数来打印你的dict,如果这个值是dict,你想用这个新的dict调用你的打印函数

类似于:

def myprint(d):
  for k, v in d.iteritems():
    if isinstance(v, dict):
      myprint(v)
    else:
      print "{0} : {1}".format(k, v)

或者对于Python 3以后的版本:

def myprint(d):
  for k, v in d.items():
    if isinstance(v, dict):
      myprint(v)
    else:
      print("{0} : {1}".format(k, v))

相关问题 更多 >