210 lines
6.7 KiB
Python
210 lines
6.7 KiB
Python
import json
|
||
import re
|
||
|
||
|
||
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
|
||
|
||
|
||
def generate_key_paths(data, parent_key='', good_list=None, seen=None):
|
||
# 保存原始顺序
|
||
original_order = get_original_order(data)
|
||
|
||
if good_list is None:
|
||
good_list = []
|
||
if seen is None:
|
||
seen = set()
|
||
|
||
key_paths = []
|
||
grouped_paths = set()
|
||
no_keys_added = True
|
||
|
||
# Step 1: Collect keys that match the pattern
|
||
pattern = re.compile(r'(.+)-\d+$')
|
||
prefix_groups = {}
|
||
other_keys = []
|
||
|
||
for key in list(data.keys()):
|
||
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:
|
||
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
|
||
key_paths.append(key_path)
|
||
if prefix not in seen:
|
||
good_list.append(prefix)
|
||
seen.add(prefix)
|
||
no_keys_added = False
|
||
|
||
# Step 3: Handle other keys (递归处理其他键)
|
||
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)
|
||
grouped_paths.update(sub_grouped_paths)
|
||
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:
|
||
good_list.append(clean_key)
|
||
seen.add(clean_key)
|
||
no_keys_added = False
|
||
else:
|
||
clean_key = key.replace(" ", "")
|
||
key_paths.append(current_key.replace(" ", ""))
|
||
if clean_key not in seen:
|
||
good_list.append(clean_key)
|
||
seen.add(clean_key)
|
||
no_keys_added = False
|
||
|
||
# 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)
|
||
|
||
return key_paths, good_list, grouped_paths, no_keys_added
|
||
|
||
# 示例使用
|
||
data1 = {
|
||
"采购需求": {
|
||
"多媒体会议厅设备": {
|
||
"LED屏显示设备": {
|
||
"户内全彩LED屏(全彩高刷)": [],
|
||
"发送盒": [],
|
||
"LED显示屏控制系统": [],
|
||
"视频处理器": [],
|
||
"智能配电柜": [],
|
||
"台式电脑": [],
|
||
"控制桌(定制)": []
|
||
},
|
||
"LED显示屏施工材料、技术服务费、包装费": {
|
||
"结构边框": [],
|
||
"线材(按需)": [],
|
||
"包装材料": []
|
||
},
|
||
"扩声系统": {
|
||
"主扩全频专业音箱": [],
|
||
"专业功放-1": [],
|
||
"专业功放-2": [],
|
||
"辅助专业音箱": [],
|
||
"壁挂支架": [],
|
||
"返听专业音箱": [],
|
||
"返听专业功放": [],
|
||
"超低频专业音箱": [],
|
||
"音箱地插": [],
|
||
"调音台": [],
|
||
"音频处理器": [],
|
||
"抑制器": [],
|
||
"无线话筒": [],
|
||
"话筒呼叫控制嵌入软件": [],
|
||
"天线分配器-1": [],
|
||
"话筒天线": [],
|
||
"有源监听音箱": [],
|
||
"电源时序器": []
|
||
},
|
||
"辅助材料": {
|
||
"机柜": [],
|
||
"音频连接线-1": [],
|
||
"音频连接线-2": [],
|
||
"音频连接线-3": [],
|
||
"其它辅材(音箱线、电源线、网线、视频线等)": []
|
||
},
|
||
"会议座椅": {
|
||
"会议座椅": []
|
||
},
|
||
"电动窗帘": {
|
||
"电动窗帘系统": []
|
||
}
|
||
},
|
||
"云平台及备课电脑": {
|
||
"备课一体机电脑": [],
|
||
"云平台管理软件": [],
|
||
"教学互动应用软件": []
|
||
},
|
||
"办公桌椅": {
|
||
"办公桌椅": []
|
||
},
|
||
"文件柜": {
|
||
"文件柜": []
|
||
},
|
||
"体育运动器材": {
|
||
"移动式标准篮球架(12座)": []
|
||
}
|
||
}
|
||
}
|
||
|
||
key_paths, good_list, grouped_paths, no_keys_added = generate_key_paths(data1)
|
||
print(json.dumps(data1,ensure_ascii=False,indent=4))
|
||
print(key_paths)
|
||
print(grouped_paths)
|