Python列表交集去重代码未达预期,原因何在?
问题:列表推导式求无重复交集失败,结果仍有重复元素
我是编程初学者,若问题过于基础还请见谅。我尝试编写代码生成两个随机列表,并通过列表推导式求出无重复的交集,但代码未达到预期效果。
代码如下:
import random a = random.choices(range(0, 10), k = 7) b = random.choices(range(0, 10), k = 7) print(a) print(b) c = [] c = [i for i in a if i in b if i not in c]
部分运行结果如下:
a = [1, 4, 1, 7, 2, 3, 8] b = [5, 6, 4, 9, 4, 4, 1] c = [1, 4, 1] a = [7, 3, 8, 4, 7, 5, 3] b = [3, 3, 7, 8, 1, 4, 7] c = [7, 3, 8, 4, 7, 3]
显然结果中包含重复元素,请问这是为什么?难道列表c不会在每次循环后更新,从而检查并排除重复元素吗?
原因分析
列表推导式的执行逻辑是:先遍历所有元素、计算所有条件,最后一次性把结果赋值给变量。你在推导式里写的i not in c,这里的c始终是初始化时的空列表[]——推导式运行全程,c都不会被实时更新,所以每次判断i not in c时,都是在和空列表对比,自然拦不住后续出现的重复元素。
拿第一次运行的例子来说:
- 遍历第一个
1:1 in b为真,1 not in []也为真,加入结果; - 遍历
4:同理加入结果; - 遍历第二个
1:此时c还是空列表,1 not in []依然为真,所以又被加进去了。
解决方案
方法1:用集合处理(最简单高效)
集合天生不允许重复元素,求交集的操作也很直接:
import random a = random.choices(range(0, 10), k = 7) b = random.choices(range(0, 10), k = 7) print(a) print(b) # 转集合去重后求交集,再转回列表 c = list(set(a) & set(b))
如果需要保留元素在a中首次出现的顺序,可以改用循环+辅助集合:
import random a = random.choices(range(0, 10), k = 7) b = random.choices(range(0, 10), k = 7) print(a) print(b) c = [] seen = set() for num in a: if num in b and num not in seen: c.append(num) seen.add(num)
方法2:改进列表推导式(借助辅助集合)
如果一定要用列表推导式,可以引入一个辅助集合来记录已添加的元素:
import random a = random.choices(range(0, 10), k = 7) b = random.choices(range(0, 10), k = 7) print(a) print(b) seen = set() c = [num for num in a if num in b and not (num in seen or seen.add(num))]
这里利用了seen.add(num)返回None的特性:如果num不在seen里,num in seen为假,就会执行seen.add(num),同时not None为真,将num加入列表;如果num已经在seen里,num in seen为真,整个条件为假,不会加入重复元素。
内容的提问来源于stack exchange,提问作者José Alberto
相关产品推荐
相关产品推荐

