2024-11-21 16:22:22 +08:00
|
|
|
|
import json
|
|
|
|
|
import re
|
|
|
|
|
|
2024-11-21 19:17:52 +08:00
|
|
|
|
|
|
|
|
|
def get_original_order(data, parent_key=''):
|
|
|
|
|
"""获取原始字典中所有键的顺序"""
|
|
|
|
|
order = []
|
|
|
|
|
for key, value in data.items():
|
|
|
|
|
current_key = f"{parent_key}.{key}" if parent_key else key
|
|
|
|
|
order.append(current_key)
|
|
|
|
|
if isinstance(value, dict):
|
|
|
|
|
order.extend(get_original_order(value, current_key))
|
|
|
|
|
return order
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def reorganize_dict(data, original_order):
|
|
|
|
|
"""根据原始顺序重新组织字典"""
|
|
|
|
|
|
|
|
|
|
def get_dict_by_path(d, path):
|
|
|
|
|
parts = path.split('.')
|
|
|
|
|
current = d
|
|
|
|
|
for part in parts[:-1]:
|
|
|
|
|
current = current[part]
|
|
|
|
|
return current
|
|
|
|
|
|
|
|
|
|
result = {}
|
|
|
|
|
# 按原始顺序重建字典结构
|
|
|
|
|
for path in original_order:
|
|
|
|
|
parts = path.split('.')
|
|
|
|
|
current = result
|
|
|
|
|
for i, part in enumerate(parts[:-1]):
|
|
|
|
|
if part not in current:
|
|
|
|
|
current[part] = {}
|
|
|
|
|
current = current[part]
|
|
|
|
|
|
|
|
|
|
# 获取原始字典中对应路径的值
|
|
|
|
|
try:
|
|
|
|
|
source_dict = get_dict_by_path(data, path)
|
|
|
|
|
current[parts[-1]] = source_dict[parts[-1]]
|
|
|
|
|
except KeyError:
|
|
|
|
|
# 如果键不存在(可能是被重命名的键),跳过
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
|
2024-11-21 17:42:32 +08:00
|
|
|
|
def generate_key_paths(data, parent_key='', good_list=None, seen=None):
|
2024-11-21 19:17:52 +08:00
|
|
|
|
# 保存原始顺序
|
|
|
|
|
original_order = get_original_order(data)
|
|
|
|
|
|
2024-11-21 17:42:32 +08:00
|
|
|
|
if good_list is None:
|
|
|
|
|
good_list = []
|
|
|
|
|
if seen is None:
|
|
|
|
|
seen = set()
|
|
|
|
|
|
|
|
|
|
key_paths = []
|
2024-11-21 19:17:52 +08:00
|
|
|
|
grouped_paths = set()
|
|
|
|
|
no_keys_added = True
|
2024-11-21 17:42:32 +08:00
|
|
|
|
|
|
|
|
|
# Step 1: Collect keys that match the pattern
|
2024-11-21 19:17:52 +08:00
|
|
|
|
pattern = re.compile(r'(.+)-\d+$')
|
2024-11-21 17:42:32 +08:00
|
|
|
|
prefix_groups = {}
|
|
|
|
|
other_keys = []
|
|
|
|
|
|
2024-11-21 19:17:52 +08:00
|
|
|
|
for key in list(data.keys()):
|
2024-11-21 17:42:32 +08:00
|
|
|
|
clean_key = key.replace(" ", "")
|
|
|
|
|
match = pattern.match(clean_key)
|
|
|
|
|
if match:
|
|
|
|
|
prefix = match.group(1)
|
|
|
|
|
if prefix not in prefix_groups:
|
|
|
|
|
prefix_groups[prefix] = []
|
|
|
|
|
prefix_groups[prefix].append(key)
|
|
|
|
|
else:
|
|
|
|
|
other_keys.append(key)
|
|
|
|
|
|
|
|
|
|
# Step 2: Handle grouped keys
|
|
|
|
|
for prefix, keys in prefix_groups.items():
|
|
|
|
|
current_prefix_path = f"{parent_key}.{prefix}" if parent_key else prefix
|
|
|
|
|
if len(keys) > 1:
|
|
|
|
|
grouped_paths.add(current_prefix_path)
|
|
|
|
|
if prefix not in seen:
|
|
|
|
|
good_list.append(prefix)
|
|
|
|
|
seen.add(prefix)
|
|
|
|
|
no_keys_added = False
|
|
|
|
|
else:
|
2024-11-21 19:17:52 +08:00
|
|
|
|
old_key = keys[0]
|
|
|
|
|
new_key = prefix
|
|
|
|
|
value = data[old_key]
|
|
|
|
|
data[new_key] = value
|
|
|
|
|
del data[old_key]
|
|
|
|
|
|
|
|
|
|
key_path = f"{parent_key}.{new_key}" if parent_key else new_key
|
2024-11-21 17:42:32 +08:00
|
|
|
|
key_paths.append(key_path)
|
|
|
|
|
if prefix not in seen:
|
|
|
|
|
good_list.append(prefix)
|
|
|
|
|
seen.add(prefix)
|
|
|
|
|
no_keys_added = False
|
|
|
|
|
|
2024-11-21 19:17:52 +08:00
|
|
|
|
# Step 3: Handle other keys (递归处理其他键)
|
2024-11-21 17:42:32 +08:00
|
|
|
|
for key in other_keys:
|
|
|
|
|
value = data[key]
|
|
|
|
|
current_key = f"{parent_key}.{key}" if parent_key else key
|
|
|
|
|
|
|
|
|
|
if isinstance(value, dict):
|
|
|
|
|
if value:
|
|
|
|
|
sub_key_paths, _, sub_grouped_paths, sub_no_keys_added = generate_key_paths(
|
|
|
|
|
value, current_key, good_list, seen
|
|
|
|
|
)
|
|
|
|
|
key_paths.extend(sub_key_paths)
|
2024-11-21 19:17:52 +08:00
|
|
|
|
grouped_paths.update(sub_grouped_paths)
|
2024-11-21 17:42:32 +08:00
|
|
|
|
no_keys_added = no_keys_added and sub_no_keys_added
|
|
|
|
|
else:
|
|
|
|
|
clean_key = key.replace(" ", "")
|
|
|
|
|
key_paths.append(current_key.replace(" ", ""))
|
|
|
|
|
if clean_key not in seen:
|
2024-11-21 19:17:52 +08:00
|
|
|
|
good_list.append(clean_key)
|
2024-11-21 17:42:32 +08:00
|
|
|
|
seen.add(clean_key)
|
|
|
|
|
no_keys_added = False
|
|
|
|
|
else:
|
|
|
|
|
clean_key = key.replace(" ", "")
|
2024-11-21 19:17:52 +08:00
|
|
|
|
key_paths.append(current_key.replace(" ", ""))
|
2024-11-21 17:42:32 +08:00
|
|
|
|
if clean_key not in seen:
|
2024-11-21 19:17:52 +08:00
|
|
|
|
good_list.append(clean_key)
|
2024-11-21 17:42:32 +08:00
|
|
|
|
seen.add(clean_key)
|
|
|
|
|
no_keys_added = False
|
|
|
|
|
|
2024-11-21 19:17:52 +08:00
|
|
|
|
# Step 4: 删除 key_paths 中包含在 grouped_paths 中的元素
|
|
|
|
|
key_paths = [path for path in key_paths if path not in grouped_paths]
|
|
|
|
|
|
|
|
|
|
# 根据原始顺序重新组织字典
|
|
|
|
|
reorganized_data = reorganize_dict(data, original_order)
|
|
|
|
|
data.clear()
|
|
|
|
|
data.update(reorganized_data)
|
|
|
|
|
|
2024-11-21 17:42:32 +08:00
|
|
|
|
return key_paths, good_list, grouped_paths, no_keys_added
|
|
|
|
|
|
|
|
|
|
# 示例使用
|
|
|
|
|
data1 = {
|
|
|
|
|
"采购需求": {
|
2024-11-21 19:17:52 +08:00
|
|
|
|
"多媒体会议厅设备": {
|
|
|
|
|
"LED屏显示设备": {
|
|
|
|
|
"户内全彩LED屏(全彩高刷)": [],
|
|
|
|
|
"发送盒": [],
|
|
|
|
|
"LED显示屏控制系统": [],
|
|
|
|
|
"视频处理器": [],
|
|
|
|
|
"智能配电柜": [],
|
|
|
|
|
"台式电脑": [],
|
|
|
|
|
"控制桌(定制)": []
|
|
|
|
|
},
|
|
|
|
|
"LED显示屏施工材料、技术服务费、包装费": {
|
|
|
|
|
"结构边框": [],
|
|
|
|
|
"线材(按需)": [],
|
|
|
|
|
"包装材料": []
|
|
|
|
|
},
|
|
|
|
|
"扩声系统": {
|
|
|
|
|
"主扩全频专业音箱": [],
|
|
|
|
|
"专业功放-1": [],
|
|
|
|
|
"专业功放-2": [],
|
|
|
|
|
"辅助专业音箱": [],
|
|
|
|
|
"壁挂支架": [],
|
|
|
|
|
"返听专业音箱": [],
|
|
|
|
|
"返听专业功放": [],
|
|
|
|
|
"超低频专业音箱": [],
|
|
|
|
|
"音箱地插": [],
|
|
|
|
|
"调音台": [],
|
|
|
|
|
"音频处理器": [],
|
|
|
|
|
"抑制器": [],
|
|
|
|
|
"无线话筒": [],
|
|
|
|
|
"话筒呼叫控制嵌入软件": [],
|
|
|
|
|
"天线分配器-1": [],
|
|
|
|
|
"话筒天线": [],
|
|
|
|
|
"有源监听音箱": [],
|
|
|
|
|
"电源时序器": []
|
|
|
|
|
},
|
|
|
|
|
"辅助材料": {
|
|
|
|
|
"机柜": [],
|
|
|
|
|
"音频连接线-1": [],
|
|
|
|
|
"音频连接线-2": [],
|
|
|
|
|
"音频连接线-3": [],
|
|
|
|
|
"其它辅材(音箱线、电源线、网线、视频线等)": []
|
|
|
|
|
},
|
|
|
|
|
"会议座椅": {
|
|
|
|
|
"会议座椅": []
|
|
|
|
|
},
|
|
|
|
|
"电动窗帘": {
|
|
|
|
|
"电动窗帘系统": []
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
"云平台及备课电脑": {
|
|
|
|
|
"备课一体机电脑": [],
|
|
|
|
|
"云平台管理软件": [],
|
|
|
|
|
"教学互动应用软件": []
|
|
|
|
|
},
|
|
|
|
|
"办公桌椅": {
|
|
|
|
|
"办公桌椅": []
|
|
|
|
|
},
|
|
|
|
|
"文件柜": {
|
|
|
|
|
"文件柜": []
|
|
|
|
|
},
|
|
|
|
|
"体育运动器材": {
|
|
|
|
|
"移动式标准篮球架(12座)": []
|
2024-11-21 17:42:32 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
key_paths, good_list, grouped_paths, no_keys_added = generate_key_paths(data1)
|
|
|
|
|
print(json.dumps(data1,ensure_ascii=False,indent=4))
|
2024-11-21 19:17:52 +08:00
|
|
|
|
print(key_paths)
|
|
|
|
|
print(grouped_paths)
|