【问题标题】:How to merge json objects containing arrays using python?如何使用python合并包含数组的json对象?
【发布时间】:2018-08-09 18:17:51
【问题描述】:

我有两个 json 文件,其中包含各种级别的属性。我想编写一个 python 脚本来替换现有属性并添加缺失的属性,但保留所有其他属性。

到目前为止,在我的尝试中,原始文件的整个“配置”数组都被覆盖了,包括所有属性。我能找到的所有示例都显示了没有数组的对象的合并。任何帮助将不胜感激。

原文:

{
  "configurations": [
    {
      "this-needs-to-stay": {
        "properties": {
          "some_property": "EXISTING"
        }
      }
    },
    {
      "this-needs-to-be-updated": {
        "properties": {
          "this.would.stay": "EXISTING",
          "this.wont.be.overwritten": "EXISTING"
        }
      }
    }
  ],
  "other-values-1": [
    {
      "components": [
        {
          "name": "EXISTING"
        }
      ],
      "name": "somename"
    }
  ],
  "other-values-2": {
    "randomProperties": {
      "type": "random"
    },
    "and_so_on": "you_get_the_point"
  }
}

应添加到原始数据的其他数据:

{
  "configurations" : [
    {
      "this-would-be-added": {
        "properties": {
          "some-property": "ADDED"
        }
      }
    },
    {
      "this-needs-to-be-updated": {
        "properties": {
          "this.would.stay": "CHANGED",
          "this.would.be.added": "ADDED"
        }
      }
    }
  ]
}

结果是两者在属性级别的合并:

{
  "configurations": [
    {
      "this-would-be-added": {
        "properties": {
          "some-property": "ADDED"
        }
      }
    },
    {
      "this-needs-to-stay": {
        "properties": {
          "some_property": "EXISTING"
        }
      }
    },
    {
      "this-needs-to-be-updated": {
        "properties": {
          "this.would.stay": "CHANGED",
          "this.would.be.added": "ADDED"
          "this.wont.be.overwritten": "EXISTING"
        }
      }
    }
  ],
  "other-values-1": [
    {
      "components": [
        {
          "name": "EXISTING"
        }
      ],
      "name": "somename"
    }
  ],
  "other-values-2": {
    "randomProperties": {
      "type": "random"
    },
    "and_so_on": "you_get_the_point"
  }
}

【问题讨论】:

    标签: python json merge array-merge


    【解决方案1】:

    使用funcy.merge

    from funcy import merge
    
    x, y = map(lambda d: {hash(frozenset(c.keys())):c for c in d}, (a['configurations'], b['configurations']))
    merged = list(merge(x, y).values())
    
    print(json.dumps(merged, indent=4))
    

    结果:

    [
        {
            "this-needs-to-stay": {
                "properties": {
                    "some_property": "EXISTING"
                }
            }
        },
        {
            "this-needs-to-be-updated": {
                "properties": {
                    "this.would.stay": "CHANGED",
                    "this.would.be.added": "ADDED"
                }
            }
        },
        {
            "this-would-be-added": {
                "properties": {
                    "some-property": "ADDED"
                }
            }
        }
    ]   
    

    【讨论】:

      【解决方案2】:

      在您的示例数据中configurations 的项目中,看起来您正在使用项目的唯一键作为数组中的唯一键。因此,我们可以使用该唯一键将列表转换为字典。

      那就是转 [{"ID_1": "VALUE_1"}, {"ID_2": "VALUE_2"}] 转入{"ID_1": "VALUE_1", "ID_2": "VALUE_2"}

      然后,我们只想合并这两个字典。这里我使用{**a, **b} 来合并它们。这部分可以看How to merge two dictionaries in a single expression?

      所以

      {"ID_1": "value_1", "ID_2": "value_2"}
      

      {"ID_2": "new_value_2", "ID_3": "new_value_3"}
      

      将被合并为

      {"ID_1": "value_1", "ID_2": "new_value_2", "ID_3": "new_value_3"}
      

      合并后,将结果字典转换回列表,这就是最终结果。

      [{"ID_1": "value_1"}, {"ID_2": "new_value_2"}, {"ID_3": "new_value_3"}]
      

      代码:

      def list_to_dict(l):
          return {list(item.keys())[0]: list(item.values())[0] for item in l}
      
      def list_item_merge(a, b):
          return [{k: v} for k, v in {**list_to_dict(a), **list_to_dict(b)}.items()]
      
      list_item_merge(original['configurations'], additional['configurations'])
      

      【讨论】:

        【解决方案3】:

        我建议检查您的 conf 结构。单键的字典列表对我来说没有意义。为什么不直接使用字典?:

        {
          "configurations": {
            "this-needs-to-stay": {
              "properties": {
                "some_property": "EXISTING"
              }
            },
            "this-needs-to-be-updated": {
              "properties": {
                "this.would.stay": "EXISTING",
                "this.wont.be.overwritten": "EXISTING"
              }
            }
        
          },
          # ...
        }
        

        那么你可以简单地使用:

        from funcy import merge
        
        conf = base
        conf['configurations'] = merge(base['configurations'],
                                       new['configurations'])
        

        【讨论】:

        • 这个 conf 结构是 Hadoop Ambari 蓝图的预定义结构。这不是我们可以影响的。
        猜你喜欢
        • 2018-12-17
        • 2017-01-16
        • 2019-07-23
        • 2013-01-08
        • 1970-01-01
        • 1970-01-01
        • 2019-11-25
        • 1970-01-01
        • 2015-09-09
        相关资源
        最近更新 更多