Python识别列表重叠合并,保证同公司下product_id跨列表唯一
解决思路
本质是对同公司下存在产品交集的集合做合并,用并查集(Union-Find)算法实现逻辑最清晰,步骤如下:
- 每个公司单独处理,先把所有(set_id, 产品列表)转成(set_id, 产品集合),方便快速判断交集
- 初始化并查集,所有set_id初始父节点为自身
- 两两遍历同公司下的所有set,若两个set的产品集合交集不为空,则合并两个set的父节点
- 按根节点分组,把同组所有set的产品合并去重,空产品列表的set无交集会单独保留
完整可运行代码
from collections import defaultdict def find(u, parent): if parent[u] != u: parent[u] = find(parent[u], parent) return parent[u] def union(u, v, parent): u_root = find(u, parent) v_root = find(v, parent) if u_root != v_root: parent[v_root] = u_root def process_data(data): result = {} for company_id, set_list in data.items(): # 存储每个set_id对应的产品集合 set_product_map = {sid: set(plist) for sid, plist in set_list} # 初始化并查集父节点 parent = {sid: sid for sid, _ in set_list} set_ids = list(set_product_map.keys()) # 两两比较合并 for i in range(len(set_ids)): s1 = set_ids[i] p1 = set_product_map[s1] # 空集合无交集,跳过 if not p1: continue for j in range(i+1, len(set_ids)): s2 = set_ids[j] p2 = set_product_map[s2] if not p2: continue # 有交集则合并 if p1 & p2: union(s1, s2, parent) # 按根节点分组合并产品 group = defaultdict(set) for sid in set_ids: root = find(sid, parent) group[root].update(set_product_map[sid]) # 转成要求的格式,产品排序可选 result[company_id] = [(root, sorted(list(plist))) for root, plist in group.items()] return result # 测试用示例数据 data = { 83: [ (128, []), (129, [19283, 23837]), (130, [29553]), (133, [19283, 20070, 20072, 20087, 20095]), (134, [20069, 20070, 20071, 20095, 20098]) ], 84: [ (145, [2322,2211]), (146, [2333, 2211]), (152, [2333]) ] } if __name__ == "__main__": res = process_data(data) print(res)
输出结果
运行上述代码输出完全符合要求:
{ 83: [ (128, []), (129, [19283, 20069, 20070, 20071, 20072, 20087, 20095, 20098, 23837]), (130, [29553]) ], 84: [(145, [2211, 2322, 2333])] }
注:合并后用哪个set_id作为最终id由并查集合并顺序决定,符合「product_id合并到任意set_id下都可」的规则,如果需要指定优先保留更大/更小的set_id,修改union方法的父节点赋值逻辑即可。
内容的提问来源于stack exchange,提问作者JoeBe
相关产品推荐
相关产品推荐

