将任意深度的平整度变平

时间:2018-12-31 15:54:14

标签: python dictionary recursion flatten

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

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

现在,我了解了如何将字典平整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中如何解决此类问题。我不得不承认我在这里有点迷路了……

非常感谢您的帮助!

2 个答案:

答案 0 :(得分:6)

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

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: {'a'}, 5: ['a', 'b'], 1: 'a'}

答案 1 :(得分:2)

您的方法是正确的。但是您已经递归更新了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']}