如何用Python合并含多层属性及数组的JSON对象?
我太懂这种踩坑的感觉了——处理带数组的JSON合并可比单纯的平面对象合并麻烦多了,直接覆盖整个数组肯定不是你想要的结果。咱们来一步步解决这个问题:
解决方案思路与代码实现
先明确场景(举个例子)
假设你的原JSON文件(original.json)结构是这样的:
{ "app_name": "My Project", "configurations": [ { "env": "dev", "api_url": "http://old-dev-api.com", "timeout": 30, "nested": { "old_key": "keep this" } }, { "env": "prod", "api_url": "http://prod-api.com" } ], "global_setting": "retain me" }
你要合并的更新JSON(update.json)是:
{ "configurations": [ { "env": "dev", "api_url": "http://new-dev-api.com", "debug_mode": true, "nested": { "new_key": "add this" } }, { "env": "staging", "api_url": "http://staging-api.com" } ], "new_global_setting": "added value" }
你的需求是:
- 全局属性:保留原有
app_name、global_setting,新增new_global_setting configurations数组:- 匹配
env为dev的项:替换api_url,新增debug_mode,合并嵌套的nested属性(保留原有old_key,添加new_key) - 保留
env为prod的原有项 - 添加
env为staging的新项
- 匹配
核心思路
- 递归合并字典:处理多层嵌套的属性,实现“替换已有键、添加缺失键”的需求,而不是直接覆盖整个子字典。
- 数组项匹配合并:通过数组项的唯一标识(比如示例中的
env)找到对应项,合并属性;同时保留原数组中未被更新的项,添加新的项。
完整Python代码
import json def merge_dicts(target, source): """递归合并两个字典:用source的键值替换target已有键,添加target没有的键(支持嵌套)""" for key, value in source.items(): if isinstance(value, dict) and key in target and isinstance(target[key], dict): # 嵌套字典,递归处理 merge_dicts(target[key], value) else: # 普通键,直接替换或添加 target[key] = value return target def merge_array_by_key(original_array, update_array, unique_key='env'): """ 合并两个数组:根据指定的唯一键匹配项,合并属性;保留原数组未被更新的项,添加新项 :param original_array: 原JSON中的数组 :param update_array: 更新JSON中的数组 :param unique_key: 数组项的唯一标识键(比如'id'、'env') """ # 把原数组转成字典,用唯一键做key,方便快速查找 original_dict = {item[unique_key]: item for item in original_array} # 遍历更新数组,合并或添加项 for item in update_array: item_key = item[unique_key] if item_key in original_dict: # 已有项,合并属性 merge_dicts(original_dict[item_key], item) else: # 新项,直接加入字典 original_dict[item_key] = item # 保持原数组的顺序,再追加新增的项(如果不需要顺序,直接返回list(original_dict.values())即可) merged_array = [] # 先加入原数组中存在的项(保留原顺序) for item in original_array: merged_array.append(original_dict[item[unique_key]]) # 加入更新数组中新增的项(不在原数组里的) original_keys = {item[unique_key] for item in original_array} update_keys = {item[unique_key] for item in update_array} new_keys = update_keys - original_keys for item in update_array: if item[unique_key] in new_keys: merged_array.append(item) return merged_array def main(): # 加载原JSON with open('original.json', 'r', encoding='utf-8') as f: original_data = json.load(f) # 加载更新JSON with open('update.json', 'r', encoding='utf-8') as f: update_data = json.load(f) # 先把更新数据中的数组单独拿出来,避免被全局合并覆盖 update_configs = update_data.pop('configurations', []) # 合并全局属性(替换已有,添加缺失) merge_dicts(original_data, update_data) # 合并configurations数组 original_configs = original_data.get('configurations', []) merged_configs = merge_array_by_key(original_configs, update_configs, unique_key='env') original_data['configurations'] = merged_configs # 保存合并后的JSON with open('merged.json', 'w', encoding='utf-8') as f: json.dump(original_data, f, indent=2, ensure_ascii=False) if __name__ == '__main__': main()
关键说明
- 递归字典合并:
merge_dicts函数会处理多层嵌套的字典,比如示例中dev项的nested属性,会保留原有old_key并添加new_key,而不是直接覆盖整个nested字典。 - 数组匹配逻辑:
merge_array_by_key函数通过唯一键(比如env)匹配数组项,确保已有项的属性被合并而非替换,同时保留原数组中未被更新的项(比如prod),并添加新项(比如staging)。 - 自定义调整:如果你的数组唯一标识不是
env,只需要修改merge_array_by_key调用时的unique_key参数即可;如果不需要保留原数组的顺序,可以简化数组合并的逻辑,直接返回list(original_dict.values())。
内容的提问来源于stack exchange,提问作者Cos
相关产品推荐
相关产品推荐

