元组列表的类排列组合生成问题:去重且保留重复元组组合
解决多重组合生成问题
嗨,我明白你要的是那种允许重复选同一个元组、但不考虑顺序的“组合”——其实这在数学里叫多重组合,正好Python的itertools库有现成的工具能搞定,比你原来的方法高效多了!
先说说你原来代码的问题:
- 用
itertools.product生成的是所有带顺序的笛卡尔积,比如你提到的[(1,20), (1,20), (1,21)]、[(1,20), (1,21), (1,20)]这些不同顺序的都会被生成,转成集合虽然能去重,但当你的元组列表变大、选取数量增多时,这种方法会生成大量冗余数据,效率很低。 - 另外你说set会丢失全重复的结果?其实不会,
((1,20), (1,20), (1,20))是可哈希的元组,会被正常保留在集合里,可能是你测试时的小疏漏~不过不管怎样,这个思路不是最优解。
正确解法:用itertools.combinations_with_replacement
这个函数就是专门为你的需求设计的:从给定序列中选取指定数量的元素,允许重复选取同一个元素,且不生成顺序不同的重复项。直接一步到位,不需要额外去重操作。
举个例子,针对你的输入:
import itertools list_of_tuples = [(1,20), (1,21), (2,18), (2,19)] # 生成选取3个元素的多重组合 results = list(itertools.combinations_with_replacement(list_of_tuples, 3))
生成的结果会包含:
- 像
((1,20), (1,20), (1,20))这样的全重复元组组合 - 对于包含不同元组的组合,比如
(1,20)和(1,21)的组合,只会保留((1,20), (1,20), (1,21))这一种(按原列表的元素顺序排列),不会出现其他顺序的版本,完全符合你“顺序不同算同一个,只保留一个”的要求。
为什么这个方法更好?
combinations_with_replacement直接生成符合要求的结果,不需要先生成所有排列再去重。比如你的例子里,它只会生成20个结果(数学上的组合数C(4+3-1,3)=20),而product会生成64个结果,再转set虽然也能得到20个,但前者的效率要高得多,尤其是当选取数量k很大的时候,差距会非常明显。
内容的提问来源于stack exchange,提问作者nirnroot
相关产品推荐
相关产品推荐

