我如何展平字典仅深于3个级别

时间:2019-05-10 09:39:08

标签: python json nested flatten

假设您有这本词典

{
    "alpha": "one",
    "beta": {
        "beta1": "two",
        "beta2": "second two"
    },
    "gamma": {
        "delta": {
            "delta1": "three",
            "delta2": "second three"
        },
        "epsilon": {
            "zeta": {
                "zeta1": "four",
                "zeta2": "second four"
            },
            "epsilon1": "five",
            "epsilon2": "second five"
        }
    }
}

并且您希望将每第3个(或更深层)的嵌套字典展平。这样的输出。

{
    "alpha": "one",
    "beta": {
        "beta1": "two",
        "beta2": "second two"
    },
    "gamma": {
        "delta": {
            "delta1": "three",
            "delta2": "second three"
        },
        "epsilon": {
            "zeta.zeta1": "four",
            "zeta.zeta2": "second four",
            "epsilon1": "five",
            "epsilon2": "second five"
        }
    }
}

人们将如何实现这一目标?

字典的标签和结构是动态的(我想重构具有不同结构但在每三个嵌套字典中有一条硬线的多个字典)

我知道我可以遍历每个值,但是当我到达第三个嵌套字典时我怎么知道?

def loopDict(d):
    for k, v in d.iteritems():
        if type(v) is dict:
            loopDict(v)
        else:
            print "{0} : {1}".format(k, v)

P.S。我可以使用flatten_json模块来压平每本字典

4 个答案:

答案 0 :(得分:1)

最简单的方法是将这一步骤分为两个步骤。将 input_dictionary 循环到所需的目标深度。然后在最里面的字典上调用展平函数:

def flatten(d):
    for key, value in list(d.items()):
        if isinstance(value, dict):
            del d[key]
            for subkey, subvalue in value.items():
                newkey = key + '.' + subkey
                d[newkey] = subvalue

for v1 in input_dict.values():
    if isinstance(v1, dict):
        for v2 in v1.values():
            if isinstance(v2, dict):
                flatten(v2)

这将输出:

{'alpha': 'one',
 'beta': {'beta1': 'two', 'beta2': 'second two'},
 'gamma': {'delta': {'delta1': 'three', 'delta2': 'second three'},
           'epsilon': {'epsilon1': 'five',
                       'epsilon2': 'second five',
                       'zeta.zeta1': 'four',
                       'zeta.zeta2': 'second four'}}}

如果需要更通用的方法,则可以使一个或两个步骤都递归。

希望这会有所帮助:-)

答案 1 :(得分:0)

我修复了!

对于查找此内容的人,我最终以这种方式对其进行了修复。

xmldict = {yourdictionary}

for k, v in xmldict.items():
    if isinstance(v, dict):
        for ke, va in v.items():
            if isinstance(va, dict):
                for key, val in va.items():
                    if isinstance(val, dict):
                        for key1, val1 in val.items():
                            if isinstance(val1, dict):
                                xmldict[k][ke][key] = flatten(v)

您可以根据深度添加或删除循环 (实际上有一个更简洁的递归函数可以为您完成此操作)

答案 2 :(得分:0)

我已解决该问题,但您速度更快!但是,我确实分享了我的答案,也许会有用

d = {
    "alpha": "one",
    "beta": {
        "beta1": "two",
        "beta2": "second two"
    },
    "gamma": {
        "delta": {
            "delta1": "three",
            "delta2": "second three"
        },
        "epsilon": {
            "zeta": {
                "zeta1": "four",
                "zeta2": "second four"
            },
            "epsilon1": "five",
            "epsilon2": "second five"
        }
    }
}


def flatten_dict(d):
    def items():
        for key, value in d.items():
            if isinstance(value, dict):
                for subkey, subvalue in flatten_dict(value).items():
                    yield key + "." + subkey, subvalue
            else:
                yield key, value

    return dict(items())

def loopDict(d, depth):
    for k, v in d.items():
        if isinstance(v, dict):
            if depth > 0:
                d[k] = flatten_dict(v)
            if depth <= 0:
                loopDict(v, depth+1)

    return d

d = loopDict(d, 0)
print(d)

答案 3 :(得分:0)

您可以使用递归:

data = {'alpha': 'one', 'beta': {'beta1': 'two', 'beta2': 'second two'}, 'gamma': {'delta': {'delta1': 'three', 'delta2': 'second three'}, 'epsilon': {'zeta': {'zeta1': 'four', 'zeta2': 'second four'}, 'epsilon1': 'five', 'epsilon2': 'second five'}}}
def flatten(d, c = [], l = 1):
   for a, b in d.items():
     if not isinstance(b, dict):
       yield a if l < 3 else '.'.join(c+[a]), b
     else:
       if l > 2:
          yield from flatten(b, c=c+[a] if l > 2 else c, l=l+1)
       else:
          yield (a, list(flatten(b, c=c+[a] if l > 2 else c, l=l+1)))

def walk(d):
  return {a:b if not isinstance(b, list) else walk(b) for a, b in d}

import json
print(json.dumps(walk(list(flatten(data))), indent=4))

输出:

{
  "alpha": "one",
  "beta": {
    "beta1": "two",
    "beta2": "second two"
  },
  "gamma": {
    "delta": {
        "delta1": "three",
        "delta2": "second three"
    },
    "epsilon": {
        "zeta.zeta1": "four",
        "zeta.zeta2": "second four",
        "epsilon1": "five",
        "epsilon2": "second five"
     }
   }
}