Loop through all nested dictionary values?
1 2 3 4 | for k, v in d.iteritems(): if type(v) is dict: for t, c in v.iteritems(): print"{0} : {1}".format(t, c) |
我正试图遍历一个字典,并打印出所有键值对,其中的值不是嵌套字典。如果值是一个字典,我想进入它并打印出它的键值对…等等。有什么帮助吗?
编辑
这个怎么样?它仍然只打印一件东西。
1 2 3 4 5 6 | def printDict(d): for k, v in d.iteritems(): if type(v) is dict: printDict(v) else: print"{0} : {1}".format(k, v) |
完整测试用例
字典:
1 2 | {u'xml': {u'config': {u'portstatus': {u'status': u'good'}, u'target': u'1'}, u'port': u'11'}} |
结果:
1 | xml : {u'config': {u'portstatus': {u'status': u'good'}, u'target': u'1'}, u'port': u'11'} |
正如Niklas所说,您需要递归,即您想要定义一个函数来打印您的dict,如果值是dict,您想要使用这个新的dict调用您的打印函数。
比如:
1 2 3 4 5 6 | def myprint(d): for k, v in d.iteritems(): if isinstance(v, dict): myprint(v) else: print"{0} : {1}".format(k, v) |
或者对于python 3之后的版本:
1 2 3 4 5 6 | def myprint(d): for k, v in d.items(): if isinstance(v, dict): myprint(v) else: print("{0} : {1}".format(k, v)) |
号
由于
1 2 3 4 5 6 7 8 | 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 |
测试:
1 2 3 4 | 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中,可能可以创建一个自定义的
在python 3中,有许多需要改进的地方。从python 3.3开始,抽象基类就生活在
1 2 3 4 5 6 7 | 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 |
如果编写自己的递归实现或与堆栈等效的迭代实现,则存在潜在的问题。请参见此示例:
1 2 3 4 5 6 7 | 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.2保存着从key1到key2.3的字典指向整个字典(后缘/循环)。当存在后缘(循环)时,堆栈/递归将无限运行。
1 2 3 4 5 6 7 8 9 | root<-------back edge / \ | _key1 __key2__ | / / \ \ | |->key1.1 key2.1 key2.2 key2.3 | / | | | value1 value2 | | | cross edge----------| |
号
如果用scharron的这个实现打印这个字典
1 2 3 4 5 6 | def myprint(d): for k, v in d.items(): if isinstance(v, dict): myprint(v) else: print"{0} : {1}".format(k, v) |
号
您将看到此错误:
1 | RuntimeError: maximum recursion depth exceeded while calling a Python object |
号
来自senderle的实现也是如此。
类似地,您可以从fred foo获得一个无限循环的实现:
1 2 3 4 5 6 7 8 | 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实际上在嵌套字典中检测循环:
1 2 3 | print dic {'key2': {'key2.1': 'value2', 'key2.3': {...}, 'key2.2': {'key1.1': 'value1'}}, 'key1': {'key1.1': 'value1'}} |
号
"…"是检测循环的位置。
根据Moondra的要求,这是一种避免循环(DFS)的方法:
1 2 3 4 5 6 7 8 9 10 11 | 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) |
号
替代迭代解:
1 2 3 4 5 6 7 8 | def myprint(d): stack = d.items() while stack: k, v = stack.pop() if isinstance(v, dict): stack.extend(v.iteritems()) else: print("%s: %s" % (k, v)) |
。
我写的版本稍有不同,在到达那里的过程中一直跟踪着钥匙。
1 2 3 4 5 6 7 8 9 10 11 | def print_dict(v, prefix=''): if isinstance(v, dict): for k, v2 in v.items(): p2 ="{}['{}']".format(prefix, k) print_dict(v2, p2) elif isinstance(v, list): for i, v2 in enumerate(v): p2 ="{}[{}]".format(prefix, i) print_dict(v2, p2) else: print('{} = {}'.format(prefix, repr(v))) |
。
在你的数据上,它会打印出来
1 2 3 | data['xml']['config']['portstatus']['status'] = u'good' data['xml']['config']['target'] = u'1' data['xml']['port'] = u'11' |
如果需要的话,也可以很容易地修改它,将前缀作为键的元组而不是字符串来跟踪。
这是一种用Python做的方法。此函数允许您循环访问所有级别中的键值对。它不会将整个内容保存到内存中,而是在循环访问时遍历dict。
1 2 3 4 5 6 7 8 9 10 11 12 | def recursive_items(dictionary): for key, value in dictionary.items(): if type(value) is dict: yield (key, value) yield from recursive_items(value) else: yield (key, value) a = {'a': {1: {1: 2, 3: 4}, 2: {5: 6}}} for key, value in recursive_items(a): print(key, value) |
号
印刷品
1 2 3 4 5 6 | a {1: {1: 2, 3: 4}, 2: {5: 6}} 1 {1: 2, 3: 4} 1 2 3 4 2 {5: 6} 5 6 |
我使用以下代码打印嵌套字典的所有值,考虑到值可能是包含字典的列表。在将JSON文件解析为字典并需要快速检查其值是否为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | d = { "user": 10, "time":"2017-03-15T14:02:49.301000", "metadata": [ {"foo":"bar"}, "some_string" ] } def print_nested(d): if isinstance(d, dict): for k, v in d.items(): print_nested(v) elif hasattr(d, '__iter__') and not isinstance(d, str): for item in d: print_nested(item) elif isinstance(d, str): print(d) else: print(d) print_nested(d) |
输出:
1 2 3 4 | 10 2017-03-15T14:02:49.301000 bar some_string |
。
下面是FredFoo对python 2的答案的修改版本。在原始响应中,只输出嵌套的最深级别。如果将键输出为列表,则可以保留所有级别的键,但要引用它们,需要引用列表列表。
功能如下:
1 2 3 4 5 6 7 | def NestIter(nested): for key, value in nested.iteritems(): if isinstance(value, collections.Mapping): for inner_key, inner_value in NestIter(value): yield [key, inner_key], inner_value else: yield [key],value |
号
要引用键:
1 2 | for keys, vals in mynested: print(mynested[keys[0]][keys[1][0]][keys[1][1][0]]) |
号
三级词典。
在访问多个键之前,您需要知道级别的数量,并且级别的数量应该是常量(在遍历值时,可以添加一小段脚本来检查嵌套级别的数量,但我还没有研究过这个问题)。
基于Scharron解决方案的列表替代解决方案
1 2 3 4 5 6 7 8 | def myprint(d): my_list = d.iteritems() if isinstance(d, dict) else enumerate(d) for k, v in my_list: if isinstance(v, dict) or isinstance(v, list): myprint(v) else: print u"{0} : {1}".format(k, v) |
作为替代方案的迭代解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | def traverse_nested_dict(d): iters = [d.iteritems()] while iters: it = iters.pop() try: k, v = it.next() except StopIteration: continue iters.append(it) if isinstance(v, dict): iters.append(v.iteritems()) else: yield k, v d = {"a": 1,"b": 2,"c": {"d": 3,"e": {"f": 4}}} for k, v in traverse_nested_dict(d): print k, v |
。
我发现这种方法有点灵活,这里您只提供了一个生成器函数,它发出键、值对,并且可以很容易地扩展到对列表进行迭代。
1 2 3 4 5 6 | def traverse(value, key=None): if isinstance(value, dict): for k, v in value.items(): yield from traverse(v, k) else: yield key, value |
然后您可以编写自己的
1 2 3 | def myprint(d): for k, v in traverse(d): print(f"{k} : {v}") |
号
测试:
1 2 3 4 5 6 7 8 9 10 11 | myprint({ 'xml': { 'config': { 'portstatus': { 'status': 'good', }, 'target': '1', }, 'port': '11', }, }) |
输出:
1 2 3 | status : good target : 1 port : 11 |
。
我在Python3.6上测试过这个。