我嵌套了json,我想将其解压缩到pandas数据帧中,我可以使用以下代码来实现。有什么方法可以修改代码以删除全局变量?
d = {
"name":"Vertebrates",
"children":[
{
"name":"Mammals",
"children":[
{
"name":"human"
},
{
"name":"chimpanzee"
}
]
},
{
"name":"Birds",
"children":[
{
"name":"chicken"
},
{
"name":"turkey"
}
]
}
]
}
path = []
def unpack(d):
global path
if len(d) == 1:
yield(d['name'], path)
else:
path.append(d['name'])
for item in d['children']:
yield from unpack(item)
path = path[:-1]
pd.DataFrame.from_dict({key:value for key, value in unpack(d)},orient='index')
编辑:
我实际上从path作为关键字参数开始,问题是我得到了这个:
('人类',['脊椎动物','哺乳动物'])
(“黑猩猩”,“脊椎动物”,“哺乳动物”))
(“鸡”,[“脊椎动物”,“哺乳动物”,“鸟”))
(“土耳其”,[“脊椎动物”,“哺乳动物”,“鸟类”))
在鸡肉和火鸡的地方,道路上仍然有哺乳动物一词, 因为在该代码中,“ path = path [:-1]”这一行无用。因此,我决定使用全局变量来确保每当递归分支完成时就删除最后一个项目。
已解决: 通过删除附加函数,blhsing的答案实际上可以解决问题。 bigwillydos的答案也可以解决问题。
我不知道在递归中变量更新在向前方向上是有效的,而在反向方向上是无效的。这就是为什么我为以后的名字积累路径的原因。
答案 0 :(得分:3)
使path
为可选参数。在初始调用中,它默认为空列表,但在递归调用中将其显式传递。
def unpack(d, path = None):
if path is None:
path = []
if len(d) == 1:
yield(d['name'], path)
else:
path.append(d['name'])
for item in d['children']:
yield from unpack(item, path)
path = path[:-1]
不要把默认值放到参数列表中;不要写:
def unpack(d, path = []):
有关说明,请参见"Least Astonishment" and the Mutable Default Argument。
答案 1 :(得分:1)
您可以将path
设置为第二个参数,而默认值为空元组。您也不需要仅在呼叫前附加项目即可在呼叫后删除项目。递归调用的调用堆栈将为您做到这一点:
def unpack(d, path=()):
if len(d) == 1:
yield(d['name'], path)
else:
for item in d['children']:
yield from unpack(item, path + (d['name'],))
答案 2 :(得分:0)
为path
函数设置unpack
静态变量
import pandas as pd
def static_vars(**kwargs):
def decorate(func):
for k in kwargs:
setattr(func, k, kwargs[k])
return func
return decorate
@static_vars(path=[])
def unpack(d):
if len(d) == 1:
yield(d['name'], unpack.path)
else:
unpack.path.append(d['name'])
for item in d['children']:
yield from unpack(item)
unpack.path = unpack.path[:-1]
def main():
d = {
"name":"Vertebrates",
"children":[
{
"name":"Mammals",
"children":[
{
"name":"human"
},
{
"name":"chimpanzee"
}
]
},
{
"name":"Birds",
"children":[
{
"name":"chicken"
},
{
"name":"turkey"
}
]
}
]
}
df = pd.DataFrame.from_dict({key:value for key, value in unpack(d)},orient='index')
print(df)
if __name__ == '__main__':
main()