Python 展平任意深度的听写

Python 展平任意深度的听写,python,dictionary,recursion,flatten,Python,Dictionary,Recursion,Flatten,我从另一个脚本收到一个包含各种类型的字典,特别是可能包含其他字典作为值的其他字典或列表 现在我想做的是创建一个简单的字典。键可能在封装的字典中出现多次。对我来说,最里面的键保存着最新的信息,所以我认为dict.update是消化“内部”dict时应用的正确例程。所谓“内部”dict,我指的是具有最外层字典某些值的字典 现在,我明白了如何将字典展平1级。我所要做的是将它任意地展平许多层 我正在处理的字典类型的一个简单示例是: d = {1: {6: {7: {2: {'a'}}}}, 2: 'b'

我从另一个脚本收到一个包含各种类型的字典,特别是可能包含其他字典作为值的其他字典或列表

现在我想做的是创建一个简单的字典。键可能在封装的字典中出现多次。对我来说,最里面的键保存着最新的信息,所以我认为
dict.update
是消化“内部”dict时应用的正确例程。所谓“内部”dict,我指的是具有最外层字典某些值的字典

现在,我明白了如何将字典展平1级。我所要做的是将它任意地展平许多层

我正在处理的字典类型的一个简单示例是:

d = {1: {6: {7: {2: {'a'}}}}, 2: 'b', 3: {4: {2: 'c'}}, 5: ['a', 'b', {1: 'a'}]}
我的尝试适用于单一深度:

dd = dict()
for k, v in d.items():
    if isinstance(v, dict):
        dd.update(v)
    elif isinstance(v, list):
        for el in v:
            if isinstance(el, dict):
                dd.update(el)
        dd[k] = [el for el in v if not isinstance(el, dict)]
    else:
        dd[k] = v
这给了我:

Out[56]:  {6: {7: {2: {'a'}}}, 2: 'b', 4: {2: 'c'}, 1: 'a', 5: ['a', 'b']}
它应该提供的是:

{2: 'a', 5: ['a', 'b']}
注意键
2
'c'
的值,而不是(我现在看到的)
'b'
。这应该是因为键
2
的最里面的值是
'c'
,而不是
'b'

我不仅仅是想得到一个功能正常的代码(尽管这会让我继续工作),我还想了解python是如何解决这个问题的。我得承认我在这里有点迷路了


非常感谢您的帮助

你的方法是正确的。但是您必须递归地更新dict,以便它在任意级别上工作

def flatten(d):
    dd = dict()
    for k, v in d.items():
        if isinstance(v, dict):
            dd.update(flatten(v))
        elif isinstance(v, list):
            for el in v:
                if isinstance(el, dict):
                    dd.update(flatten(el))
            dd[k] = [el for el in v if not isinstance(el, dict)]
        else:
            dd[k] = v

    return dd

d = {1: {2: {'a'}}, 2: 'b', 3: {4: {2: 'c'}}, 5: ['a', 'b', {1: 'a'}]}
print flatten(d)
# {2: 'c', 1: 'a', 5: ['a', 'b']}

可以对生成器使用递归,并保留一个计数器来确定深度:

d = {1: {6: {7: {2: {'a'}}}}, 2: 'b', 3: {4: {2: 'c'}}, 5: ['a', 'b', {1: 'a'}]}
def flatten(_d, _depth = 0):
  for a, b in _d.items():
     if isinstance(b, list):
       yield [a, [i for i in b if not isinstance(i, dict)], _depth]
       for c in b:
          if isinstance(c, dict):
             yield from flatten(c, _depth+1)
     elif isinstance(b, dict):
        yield from flatten(b, _depth+1)
     else:
        yield [a, b, _depth]

_result = {}
for a, b, c in flatten(d):
  if a not in _result:
     _result[a] = [b, c]
  else:
     if _result[a][-1] < c:
       _result[a] = [b, c]
print({a:b for a, [b, c] in _result.items()})

{2:c',1:a',5:['a',b']}
是您想要的输出吗?
4
不应该出现在它的某个地方吗?@Ajax1234是的,这是所需的输出!实际上,
4
不再存在是正确的,因为键
4
包含一个
dict
,其内容在顶层导入。不确定我是否清楚地表达了自己,因此原则上可能存在
4:{}
,但它不包含任何信息,因此可以删除。实际上,看看这个库:,您使用的是哪个操作系统?,因为这会影响你如何安装它library@user904542macOS或linux有时这有时那。。。谢谢你的链接,我来看看这个@用户904542,但这仅适用于numpy阵列。我有一个
dict
对象,它包含所有类型的对象,特别是
int
float
列表
dict
元组
布尔
。很好,这实际上看起来并不复杂!但是这总是使用最里面的值作为键吗?如果我使用
d={1:{6:{7:{2:{'a'}}}},2:'b',3:{4:{2:'c'},5:['a',b',{1:'a'}}
然后输出dict有一对
2:'c'
,但它应该有一对
2:'a'
,因为
'a'
是键
2
的最里面的值。我更新到question以捕获“深度”问题。所以我会直接用
d=dict(展平(d))
,对吗?!但是在这里,如果你设置
d={1:{6:{7:{2:{'a'}}}},2:'b',3:{4:{2:'c'},5:['a',b',{1:'a'}}
则输出dict有一对
2:'c'
但它应该有一对
2:'a'
作为
'a'
键的最内部值,请参见我最近的编辑,我刚刚添加了一个解决方案来反映这一点。哇,这看起来很复杂。我是否理解正确:将深度作为一个参数,然后再次运行展平的
dict
,并使用具有最高深度的值,对吗@是的,没错。顺便说一句,非常感谢你愿意帮忙!
{2: {'a'}, 5: ['a', 'b'], 1: 'a'}