Python 如何完全遍历未知深度的复杂字典?
从Python 如何完全遍历未知深度的复杂字典?,python,json,dictionary,python-2.7,Python,Json,Dictionary,Python 2.7,从JSON导入可以得到非常复杂的嵌套结构。 例如: {u'body': [{u'declarations': [{u'id': {u'name': u'i', u'type': u'Identifier'}, u'init': {u'type': u'Literal', u'value': 2},
JSON
导入可以得到非常复杂的嵌套结构。
例如:
{u'body': [{u'declarations': [{u'id': {u'name': u'i',
u'type': u'Identifier'},
u'init': {u'type': u'Literal', u'value': 2},
u'type': u'VariableDeclarator'}],
u'kind': u'var',
u'type': u'VariableDeclaration'},
{u'declarations': [{u'id': {u'name': u'j',
u'type': u'Identifier'},
u'init': {u'type': u'Literal', u'value': 4},
u'type': u'VariableDeclarator'}],
u'kind': u'var',
u'type': u'VariableDeclaration'},
{u'declarations': [{u'id': {u'name': u'answer',
u'type': u'Identifier'},
u'init': {u'left': {u'name': u'i',
u'type': u'Identifier'},
u'operator': u'*',
u'right': {u'name': u'j',
u'type': u'Identifier'},
u'type': u'BinaryExpression'},
u'type': u'VariableDeclarator'}],
u'kind': u'var',
u'type': u'VariableDeclaration'}],
u'type': u'Program'}
建议以什么方式行走上述复杂结构
除了少数几个列表外,大部分都是字典,结构可能会变得更加复杂,因此我需要一个通用的解决方案。如果您只需要遍历字典,我建议使用递归的
walk
函数,该函数获取字典,然后递归遍历其元素。大概是这样的:
def walk(node):
for key, item in node.items():
if item is a collection:
walk(item)
else:
It is a leaf, do your thing
Other.Stuff.Here.Key=Value
root1.height=1.9
root1.surname=Fabiano
root1.name=Silos
root1.address.country=Brazil
root1.address.x=Pinheiros
root1.address.city=Sao
root2.height=1.78
root2.surname=My
root2.name=Friend
root2.address.country=Brazil
root2.address.detail.neighbourhood=Central
root2.address.city=Recife
如果您还想搜索元素,或查询通过某些条件的多个元素,请查看该模块。您可以使用递归生成器将字典转换为平面列表
def dict_generator(indict, pre=None):
pre = pre[:] if pre else []
if isinstance(indict, dict):
for key, value in indict.items():
if isinstance(value, dict):
for d in dict_generator(value, pre + [key]):
yield d
elif isinstance(value, list) or isinstance(value, tuple):
for v in value:
for d in dict_generator(v, pre + [key]):
yield d
else:
yield pre + [key, value]
else:
yield pre + [indict]
它回来了
[u'body', u'kind', u'var']
[u'init', u'declarations', u'body', u'type', u'Literal']
[u'init', u'declarations', u'body', u'value', 2]
[u'declarations', u'body', u'type', u'VariableDeclarator']
[u'id', u'declarations', u'body', u'type', u'Identifier']
[u'id', u'declarations', u'body', u'name', u'i']
[u'body', u'type', u'VariableDeclaration']
[u'body', u'kind', u'var']
[u'init', u'declarations', u'body', u'type', u'Literal']
[u'init', u'declarations', u'body', u'value', 4]
[u'declarations', u'body', u'type', u'VariableDeclarator']
[u'id', u'declarations', u'body', u'type', u'Identifier']
[u'id', u'declarations', u'body', u'name', u'j']
[u'body', u'type', u'VariableDeclaration']
[u'body', u'kind', u'var']
[u'init', u'declarations', u'body', u'operator', u'*']
[u'right', u'init', u'declarations', u'body', u'type', u'Identifier']
[u'right', u'init', u'declarations', u'body', u'name', u'j']
[u'init', u'declarations', u'body', u'type', u'BinaryExpression']
[u'left', u'init', u'declarations', u'body', u'type', u'Identifier']
[u'left', u'init', u'declarations', u'body', u'name', u'i']
[u'declarations', u'body', u'type', u'VariableDeclarator']
[u'id', u'declarations', u'body', u'type', u'Identifier']
[u'id', u'declarations', u'body', u'name', u'answer']
[u'body', u'type', u'VariableDeclaration']
[u'type', u'Program']
更新:注释中提到的从
[key]+pre
到pre+[key]
的固定键列表。如果您知道数据的含义,可能需要创建一个解析
函数,将嵌套容器转换为自定义类型的对象树。然后,您将使用这些自定义对象的方法来处理数据
对于示例数据结构,您可以创建程序
,变量声明
,变量声明器
,标识符
,文字
和二进制表达式
类,然后对解析器使用类似的内容:
def parse(d):
t = d[u"type"]
if t == u"Program":
body = [parse(block) for block in d[u"body"]]
return Program(body)
else if t == u"VariableDeclaration":
kind = d[u"kind"]
declarations = [parse(declaration) for declaration in d[u"declarations"]]
return VariableDeclaration(kind, declarations)
else if t == u"VariableDeclarator":
id = parse(d[u"id"])
init = parse(d[u"init"])
return VariableDeclarator(id, init)
else if t == u"Identifier":
return Identifier(d[u"name"])
else if t == u"Literal":
return Literal(d[u"value"])
else if t == u"BinaryExpression":
operator = d[u"operator"]
left = parse(d[u"left"])
right = parse(d[u"right"])
return BinaryExpression(operator, left, right)
else:
raise ValueError("Invalid data structure.")
根据任务的不同,您可以从标准库
json
模块扩展编码器和解码器,而不是编写自己的解析器
我建议这样做,特别是当您需要将属于自定义类的对象编码到json中时。如果必须做一些操作,也可以在JSON的字符串表示上进行,那么也要考虑JSONECODE()的迭代。
对于这两种情况,参考是可能会有帮助:
def walk(d):
global path
for k,v in d.items():
if isinstance(v, str) or isinstance(v, int) or isinstance(v, float):
path.append(k)
print "{}={}".format(".".join(path), v)
path.pop()
elif v is None:
path.append(k)
## do something special
path.pop()
elif isinstance(v, dict):
path.append(k)
walk(v)
path.pop()
else:
print "###Type {} not recognized: {}.{}={}".format(type(v), ".".join(path),k, v)
mydict = {'Other': {'Stuff': {'Here': {'Key': 'Value'}}}, 'root1': {'address': {'country': 'Brazil', 'city': 'Sao', 'x': 'Pinheiros'}, 'surname': 'Fabiano', 'name': 'Silos', 'height': 1.9}, 'root2': {'address': {'country': 'Brazil', 'detail': {'neighbourhood': 'Central'}, 'city': 'Recife'}, 'surname': 'My', 'name': 'Friend', 'height': 1.78}}
path = []
walk(mydict)
将产生如下输出:
def walk(node):
for key, item in node.items():
if item is a collection:
walk(item)
else:
It is a leaf, do your thing
Other.Stuff.Here.Key=Value
root1.height=1.9
root1.surname=Fabiano
root1.name=Silos
root1.address.country=Brazil
root1.address.x=Pinheiros
root1.address.city=Sao
root2.height=1.78
root2.surname=My
root2.name=Friend
root2.address.country=Brazil
root2.address.detail.neighbourhood=Central
root2.address.city=Recife
对上述解决方案的一些补充(处理json,包括列表)
如果接受的答案对您有效,但您也希望使用包含嵌套数组数字索引的完整、有序的路径,那么这种细微的变化将起作用:
def dict_生成器(indicate,pre=None):
pre=pre[:]如果pre-else[]
如果不存在(起诉、命令):
对于键,indicate.items()中的值:
如果isinstance(值,dict):
对于dict_生成器中的d(值,前置+[键]):
产量d
elif isinstance(值,列表)或isinstance(值,元组):
对于枚举中的k,v(值):
对于dict_生成器中的d(v,pre+[key]+[k]):
产量d
其他:
收益率前+[键,值]
其他:
产量指标
我更灵活的版本如下:
def walktree(树,at=lambda节点:非isinstance(节点,dict),前缀=(),
FlattNode=lambda节点:isinstance(节点,(列表、元组、集合)):
"""
遍历树,并返回从根节点到叶节点的路径的迭代器。
树:像“{'a':{'b':1,'c':2}”
at:bool函数或int表示要降低的级别num。walktree(tree,at=1)相当于tree.items()
FlattNode:一个bool函数,用于决定是否在节点值处迭代
"""
如果isinstance(at,int):
isleaf_Uat==0
isleaf=λv:isleaf_
at=at-1
其他:
isleaf=at
如果是isleaf(树):
如果未展平节点(树):
产量(*前缀,树)
其他:
对于树中的v:
walktree的产量(v、at、前缀、FlattNode=FlattNode)
其他:
对于树中的k,v.items():
来自walktree的产量(v,at,(*前缀,k),FlattNode=FlattNode)
用法:
>列表(walktree({'a':{'b':[0,1],'c':2},'d':3}))
[('a','b',0),('a','b',1),('a','c',2),('d',3)]
>列表(walktree({'a':{'b':[0,1],'c':2},'d':3},flattNode=lambda e:False))
[('a','b',[0,1]),('a','c',2),('d',3)]
>列表(walktree({'a':{'b':[0,1],'c':2},'d':3},at=1))
[('a',{'b':[0,1],'c':2}),('d',3)]
>列表(walktree({'a':{'b':[0,{1:9,9:1}],'c':2},'d':3}))
[('a','b',0),('a','b',1,9),('a','b',9,1),('a','c',2),('d',3)]
>列表(walktree([1,2,3,4,5]]))
[(1,), (2,), (3,), (4,), (5,)]
您想用字典做什么?这只适用于直接嵌套的字典。在示例数据结构中,有几个字典值是其他字典的列表。需要一些额外的逻辑来处理这些问题(例如在列表理解或生成器表达式中递归)。为了使事情正常运行,您可能需要使用您对数据含义的知识,例如所有字典都有一个“type”键。您还应该仔细检查循环。e、 g.:foo={};foo[bar]=foo会把你炸飞的。您的walk函数应该保留它所看到的对象的列表,而不是下降。(您可以将列表传递给每个后续调用)如果项是集合,则抛出错误。您的导入声明是什么?我正在阅读的所有解决方案中,这是最简单的,效果很好:-)感谢Bryukhanov ValentinGreat解决方案,但您有一个错误,“[key]+pre”应该是“pre+[key]”。否则返回的列表会使路径变得混乱。我还想在列表/元组child的情况下获取索引。我通过添加enumerate
实现了这一点,并做了如下操作:对于枚举中的I,v(value):对于dict_生成器中的d(v,pre+[key+f'[{I}]'):
Full:(它是Python,而不是C#)它工作得很好。它生成树中路径的完整列表。每个列表一条路径。mypaths=[*dict_generator(myjson)]对于mypaths:print(path)中的路径,请考虑避免发布包含大量内容的长答案code@Khaled代码的大小,在我看来,代码对于所需的内容来说是最小的