Python实现含重复元素的列表交集(保留重复次数)
带重复元素列表的交集求解问题
需求:找出两个含重复元素的列表的交集,交集中元素的重复次数取两列表中该元素出现次数的最小值。
测试案例1
对比列表
list1 = ['Q', 'U', 'Z', 'Z'] list2 = ['Q', 'U', 'I', 'Z']
用户实现代码
common = [] for letter in list1: # QUZZ if letter in list2: # QUIZ --- 此条件存在问题(会添加两个Z而不是一个) common.append(letter) print(common)
期望输出
Common = ['Q', 'U', 'Z']
实际输出
Common = ['Q', 'U', 'Z', 'Z']
问题分析
这段代码没有考虑list2中元素的剩余可用次数,只要元素存在于list2中就会添加到结果里,导致list1中的两个Z都被保留,不符合list2仅含一个Z的限制。
测试案例2
对比列表
list1 = ['Z','Z','Z','Z','E','E'] list2= ['Z', 'Z', 'Z']
用户尝试的集合方法代码
print(list(set([x for x in list1 if x in list2])))
期望输出
['Z','Z','Z']
实际输出
['Z']
问题分析
集合的核心特性是去重,即便筛选出了list1中所有符合条件的Z,转成集合后只会保留唯一实例,无法满足保留指定重复次数的需求。
正确解决方案
方法1:利用collections.Counter(推荐)
Counter可以便捷统计元素出现次数,通过取两个Counter的交集(元素取共有项,次数取最小值),再展开为列表即可:
from collections import Counter def intersect_with_duplicates(list_a, list_b): counter_a = Counter(list_a) counter_b = Counter(list_b) # 计算交集,自动取元素出现次数的最小值 common_counter = counter_a & counter_b # 将Counter展开为列表 return list(common_counter.elements()) # 测试案例1 list1 = ['Q', 'U', 'Z', 'Z'] list2 = ['Q', 'U', 'I', 'Z'] print(intersect_with_duplicates(list1, list2)) # 输出: ['Q', 'U', 'Z'] # 测试案例2 list1 = ['Z','Z','Z','Z','E','E'] list2= ['Z', 'Z', 'Z'] print(intersect_with_duplicates(list1, list2)) # 输出: ['Z', 'Z', 'Z']
方法2:手动统计次数
如果不想引入collections模块,可以手动统计list2的元素次数,遍历list1时按需减少计数并添加元素:
def intersect_with_duplicates(list_a, list_b): # 统计list2中各元素的出现次数 count_b = {} for item in list_b: count_b[item] = count_b.get(item, 0) + 1 common = [] for item in list_a: # 仅当list2中该元素还有剩余次数时才添加 if count_b.get(item, 0) > 0: common.append(item) count_b[item] -= 1 return common # 测试案例1 list1 = ['Q', 'U', 'Z', 'Z'] list2 = ['Q', 'U', 'I', 'Z'] print(intersect_with_duplicates(list1, list2)) # 输出: ['Q', 'U', 'Z'] # 测试案例2 list1 = ['Z','Z','Z','Z','E','E'] list2= ['Z', 'Z', 'Z'] print(intersect_with_duplicates(list1, list2)) # 输出: ['Z', 'Z', 'Z']
内容的提问来源于stack exchange,提问作者gaurav8936
相关产品推荐
相关产品推荐

