Python中更新含重复键字典并保留键索引的实现方案
解决Python中保留JSON重复键并按顺序更新的问题
核心问题
Python原生dict不支持重复键,默认json.load会将JSON解析为dict并自动合并重复键(后续键覆盖前置键),dict.update()或|操作也会丢失重复键,无法满足保留原键顺序+保留重复键的更新需求。
解决方案步骤
1. 加载JSON时保留重复键与原始顺序
不用默认的dict解析,将JSON转换为键值对列表,完整保留原始结构:
import json def load_json_with_duplicates(file_path): with open(file_path, 'r', encoding='utf-8') as f: # 使用object_pairs_hook将JSON对象解析为(key, value)元组的列表 return json.load(f, object_pairs_hook=lambda pairs: pairs) # 加载payload,得到键值对列表 payload_pairs = load_json_with_duplicates("payload.json")
2. 重构info为键值对列表
由于Pythondict会自动丢弃重复键,必须将需要更新的内容定义为键值对列表,确保所有重复键都被保留:
# 注意:不能用dict定义,否则重复的"select"会被覆盖 info_pairs = [ ("name", "Spock"), ("ethnicities", "Vulcan"), ("select", "paternal"), ("sub-ethnicities", "human"), ("select", "maternal"), ("Extra-ethnicities", "Asian"), ("select", "Asian") ]
3. 按顺序更新payload
遍历原始payload的键值对,依次匹配info中的内容,替换对应值;剩余的新增键值对可插入到指定位置(示例中追加到原payload末尾):
# 将info转换为迭代器,逐个取出需要更新的键值对 info_iter = iter(info_pairs) current_key, current_val = next(info_iter, (None, None)) updated_pairs = [] for key, val in payload_pairs: # 匹配到当前需要更新的键时,替换值并取下一个info项 if key == current_key and current_key is not None: updated_pairs.append((key, current_val)) current_key, current_val = next(info_iter, (None, None)) else: updated_pairs.append((key, val)) # 将info中剩余的新增键值对追加到末尾(可根据需求调整插入位置) while current_key is not None: updated_pairs.append((current_key, current_val)) current_key, current_val = next(info_iter, (None, None))
4. 生成带重复键的JSON字符串
自定义JSON编码器,将键值对列表转换为符合需求的JSON格式(默认json.dumps会将列表转为数组,这里需要手动生成对象结构):
class DuplicateKeyJSONEncoder(json.JSONEncoder): def encode(self, obj): # 处理键值对列表,生成带重复键的JSON对象 if isinstance(obj, list) and all(isinstance(item, tuple) and len(item)==2 for item in obj): parts = [] for k, v in obj: # 分别序列化键和值,避免格式错误 key_str = json.dumps(k) val_str = json.dumps(v) parts.append(f"{key_str}: {val_str}") return "{" + ", ".join(parts) + "}" # 其他类型用默认逻辑处理 return super().encode(obj) # 生成最终的JSON字符串,保留缩进 final_json = json.dumps(updated_pairs, cls=DuplicateKeyJSONEncoder, indent=4) print(final_json)
输出结果
运行后会得到符合预期的JSON,保留原键顺序与所有重复键:
{ "name": "Spock", "address": "", "age": " ", "ethnicities": "Vulcan", "select": "paternal", "sub-ethnicities": "human", "select": "maternal", "option1": "", "option2": "", "Extra-ethnicities": "Asian", "select": "Asian" }
注意事项
- JSON标准允许重复键,但多数第三方解析器会忽略或覆盖重复键,仅适用于明确支持重复键的目标系统。
- 若需要插入新增键到指定位置(而非末尾),可修改遍历逻辑,在特定位置插入对应的键值对。
内容的提问来源于stack exchange,提问作者JrBusiness
相关产品推荐
相关产品推荐

