【问题标题】:How do I flatten dictionary's only deeper than 3 levels我如何将字典的平面展平仅深于 3 个级别
【发布时间】:2019-09-28 04:47:11
【问题描述】:

假设你有这本词典

{
    "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)

附:我可以使用flatten_json 模块来展平每个字典

【问题讨论】:

  • 你能解释一下你想用这个解决什么问题吗?通常扁平化这样的结构不会改善数据处理。
  • 按照你想要的方式处理数据会很糟糕
  • 您可以在loopDict 函数中添加一个“级别”/“深度”参数,并在每次递归时增加它,这就是为什么您知道何时达到第三级。

标签: python json nested flatten


【解决方案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'}}}

如果需要更通用的东西,可以使其中一个或两个步骤都递归。

希望这会有所帮助:-)

【讨论】:

    【解决方案2】:

    你可以使用递归:

    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"
         }
       }
    }
    

    【讨论】:

      【解决方案3】:

      我解决了这个问题,但你更快!但是,我确实分享了我的答案,也许它会很有用

      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)
      

      【讨论】:

        【解决方案4】:

        我修好了!

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

        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)
        

        您可以根据深度添加或删除 for 循环 (有一个简洁的递归函数可以为你做到这一点)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-05-28
          • 1970-01-01
          • 2017-03-06
          • 2020-11-06
          • 2023-03-26
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多