Python itertools.product生成笛卡尔积时剔除同模式配置的方法
问题背景
现有3个独立位置,每个位置可从集合{1, 2, 3}中取值,初始通过如下Python代码调用itertools.product生成全部笛卡尔积结果:
import itertools options = [1, 2, 3] for element in itertools.product(options, options, options): print(element)
运行后共得到27条全量结果:
(1, 1, 1) (1, 1, 2) (1, 1, 3) (1, 2, 1) (1, 2, 2) (1, 2, 3) (1, 3, 1) (1, 3, 2) (1, 3, 3) (2, 1, 1) (2, 1, 2) (2, 1, 3) (2, 2, 1) (2, 2, 2) (2, 2, 3) (2, 3, 1) (2, 3, 2) (2, 3, 3) (3, 1, 1) (3, 1, 2) (3, 1, 3) (3, 2, 1) (3, 2, 2) (3, 2, 3) (3, 3, 1) (3, 3, 2) (3, 3, 3)
业务需要剔除同配置模式的冗余结果,同模式判定规则为:仅和值的分布结构有关,和具体取值、值所在的位置无关,示例如下:
- 保留
(1, 1, 1)时,可剔除(2, 2, 2)、(3, 3, 3),三者同属所有位置取值完全相同的模式 - 保留
(1, 1, 2)时,可剔除(2, 2, 3)、(2, 2, 1)、(1, 2, 1)、(3, 1, 3)等所有结果,这类结果同属两个位置取值相同,剩余位置取值不同的模式 - 剩余所有三个位置取值完全不同的结果,同属第三类模式
实现方案
核心思路是为每个元组生成唯一的模式签名:同模式的元组签名完全一致,不同模式的元组签名不同。遍历全量结果时,仅保留每个签名第一次出现的元组,其余同签名结果直接剔除即可。
针对当前规则,签名生成逻辑为:统计元组中每个值的出现次数,将次数按降序排序后转为元组,作为该元组的模式签名。该签名和具体取值、值的位置无关,仅反映值的频次分布,完全匹配规则要求:
- 全值相同的元组,频次统计结果为
[3],签名固定为(3,) - 两同一异的元组,频次统计结果为
[2, 1],签名固定为(2,1) - 三值全异的元组,频次统计结果为
[1,1,1],签名固定为(1,1,1)
完整代码
import itertools from collections import Counter def get_pattern_signature(tpl): # 统计值出现频次,按降序排序生成签名 count_list = sorted(Counter(tpl).values(), reverse=True) return tuple(count_list) options = [1, 2, 3] seen_patterns = set() filtered_result = [] for element in itertools.product(options, repeat=3): sig = get_pattern_signature(element) if sig not in seen_patterns: seen_patterns.add(sig) filtered_result.append(element) # 打印去重后的结果 for item in filtered_result: print(item)
运行结果
执行后最终保留3个覆盖所有配置模式的代表元组,无冗余:
(1, 1, 1) (1, 1, 2) (1, 2, 3)
如果需要调整保留的代表元组(比如保留大值在前的结果),只需要调整options的遍历顺序即可。如果后续模式规则变更(比如位置需要区分、值映射规则调整),只需要修改get_pattern_signature函数的签名生成逻辑即可,主流程不需要变动。
内容的提问来源于stack exchange,提问作者Saif
相关产品推荐
相关产品推荐

