遍历列表删除元素异常:{1,3}未被移除问题排查
问题描述
我写了一段代码,想从combi列表里移除所有存在于teamed中的集合,但运行结果不对——{1,3}明明在teamed里却没被移除,而且循环根本没遍历到这个元素。
原代码如下:
import itertools # 补充原代码遗漏的导入 teamed = [{1, 2}, {3, 4}, {5, 6}, {8, 7}, {9, 10}, {11, 12}, {1, 3}, {2, 4}, {5, 7}, {8, 6}, {9, 13}, {10, 14}] game_3 = [1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14] combi = [set(combo) for combo in itertools.combinations(game_3, 2)] for c in combi: if c in teamed: combi.remove(c) print(combi)
运行后结果仍包含{1,3}:
[{1, 3}, {1, 4}, {1, 5}, {1, 6}, {1, 7}, {8, 1}, {1, 11}, {1, 12}, {1, 13}, {1, 14}, {2, 3}, {2, 5}, {2, 6}, {2, 7}, {8, 2}, {2, 11}, {2, 12}, {2, 13}, {2, 14}, {3, 5}, {3, 6}, {3, 7}, {8, 3}, {11, 3}, {3, 12}, {3, 13}, {3, 14}, {4, 5}, {4, 6}, {4, 7}, {8, 4}, {11, 4}, {4, 12}, {4, 13}, {4, 14}, {5, 7}, {8, 5}, {11, 5}, {12, 5}, {13, 5}, {5, 14}, {6, 7}, {11, 6}, {12, 6}, {13, 6}, {6, 14}, {11, 7}, {12, 7}, {13, 7}, {14, 7}, {8, 11}, {8, 12}, {8, 13}, {8, 14}, {11, 13}, {11, 14}, {12, 13}, {12, 14}, {13, 14}]
问题原因
直接在遍历列表的同时调用remove修改列表,会导致遍历索引混乱。比如移除第i个元素后,后面的元素会往前移位,原本的第i+1个元素变成了第i个,但循环索引会直接跳到i+1,从而跳过了这个元素——这就是{1,3}没被遍历到的核心原因。
解决方案
方案1:遍历列表副本
遍历combi的副本,修改原列表不会影响遍历过程:
import itertools teamed = [{1, 2}, {3, 4}, {5, 6}, {8, 7}, {9, 10}, {11, 12}, {1, 3}, {2, 4}, {5, 7}, {8, 6}, {9, 13}, {10, 14}] game_3 = [1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14] combi = [set(combo) for combo in itertools.combinations(game_3, 2)] # 遍历combi的副本,避免修改原列表干扰遍历 for c in list(combi): if c in teamed: combi.remove(c) print(combi)
方案2:列表推导式过滤(推荐)
直接生成新列表过滤掉不需要的元素,代码更简洁高效:
import itertools teamed = [{1, 2}, {3, 4}, {5, 6}, {8, 7}, {9, 10}, {11, 12}, {1, 3}, {2, 4}, {5, 7}, {8, 6}, {9, 13}, {10, 14}] game_3 = [1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14] combi = [set(combo) for combo in itertools.combinations(game_3, 2)] # 列表推导式直接过滤掉在teamed中的元素 combi = [c for c in combi if c not in teamed] print(combi)
方案3:优化查找效率(大数据量场景)
如果teamed元素很多,列表查找c in teamed效率很低(O(n)),可以把teamed转成frozenset的集合(普通集合不可哈希,不能作为集合元素),提升查找速度:
import itertools # 将teamed转为frozenset的集合,把查找复杂度降到O(1) teamed = {frozenset(s) for s in [{1, 2}, {3, 4}, {5, 6}, {8, 7}, {9, 10}, {11, 12}, {1, 3}, {2, 4}, {5, 7}, {8, 6}, {9, 13}, {10, 14}]} game_3 = [1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14] combi = [set(combo) for combo in itertools.combinations(game_3, 2)] # 过滤时将元素转为frozenset判断 combi = [c for c in combi if frozenset(c) not in teamed] print(combi)
内容的提问来源于stack exchange,提问作者Karim Omar
相关产品推荐
相关产品推荐

