以下是python中的几种不同方法
三重嵌套循环
我们通过迭代第一个元素的所有可能值、迭代第二个元素的所有可能值以及迭代第三个元素的所有可能值来找到所有可能的三元组。
- 优点:理解和编码极其简单;
- 缺点:每个元组的元素数量是硬编码的;如果我们想要对、四胞胎或五胞胎而不是三胞胎,我们需要一个不同的函数。
def all_triplets(seq):
for x in seq:
for y in seq:
for z in seq:
yield (x,y,z)
print(list(all_triplets('AB')))
# [('A', 'A', 'A'), ('A', 'A', 'B'), ('A', 'B', 'A'), ('A', 'B', 'B'), ('B', 'A', 'A'), ('B', 'A', 'B'), ('B', 'B', 'A'), ('B', 'B', 'B')]
print(list(all_triplets('ABC')))
# [('A', 'A', 'A'), ('A', 'A', 'B'), ('A', 'A', 'C'), ('A', 'B', 'A'), ('A', 'B', 'B'), ('A', 'B', 'C'), ('A', 'C', 'A'), ('A', 'C', 'B'), ('A', 'C', 'C'), ('B', 'A', 'A'), ('B', 'A', 'B'), ('B', 'A', 'C'), ('B', 'B', 'A'), ('B', 'B', 'B'), ('B', 'B', 'C'), ('B', 'C', 'A'), ('B', 'C', 'B'), ('B', 'C', 'C'), ('C', 'A', 'A'), ('C', 'A', 'B'), ('C', 'A', 'C'), ('C', 'B', 'A'), ('C', 'B', 'B'), ('C', 'B', 'C'), ('C', 'C', 'A'), ('C', 'C', 'B'), ('C', 'C', 'C')]
递归关系
我们使用笛卡尔积的递归关系代替嵌套循环:
product(seq with itself n times) == product(seq, product(seq with itself n-1 times))
我们仍然会迭代第一个元素的所有可能值;但是我们不会使用硬编码的嵌套循环来迭代剩余元素的所有可能值,而是使用递归关系来获取剩余元素的可能值。
像所有递归关系一样,它可以很容易地用于编写迭代函数或递归函数。由于python在递归方面非常糟糕,这里有一个迭代版本。
- 优点:每个元组的元素数量现在是一个参数;
- 缺点:这比硬编码的嵌套循环更难理解。
def all_n_uplets(seq, n):
'''assume n >= 1'''
result = seq
for _ in range(n-1):
result = [ (x, *t) for x in seq for t in result ]
return result
print(all_n_uplets('ABC', 2))
# [('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'B'), ('B', 'C'), ('C', 'A'), ('C', 'B'), ('C', 'C')]
print(all_n_uplets('ABC', 3))
# [('A', 'A', 'A'), ('A', 'A', 'B'), ('A', 'A', 'C'), ('A', 'B', 'A'), ('A', 'B', 'B'), ('A', 'B', 'C'), ('A', 'C', 'A'), ('A', 'C', 'B'), ('A', 'C', 'C'), ('B', 'A', 'A'), ('B', 'A', 'B'), ('B', 'A', 'C'), ('B', 'B', 'A'), ('B', 'B', 'B'), ('B', 'B', 'C'), ('B', 'C', 'A'), ('B', 'C', 'B'), ('B', 'C', 'C'), ('C', 'A', 'A'), ('C', 'A', 'B'), ('C', 'A', 'C'), ('C', 'B', 'A'), ('C', 'B', 'B'), ('C', 'B', 'C'), ('C', 'C', 'A'), ('C', 'C', 'B'), ('C', 'C', 'C')]
标准库
笛卡尔积已经在python中实现:it's function product in module itertools.它可以用来计算几个不同序列的笛卡尔积,或者一个序列与它自己的笛卡尔积。
- 优点:它已经存在,无需重新实现轮子;
- 缺点:名称
itertools.product 是特定于 python 的,如果您想使用其他语言,则需要寻找对应的名称。
from itertools import product
print(list(product('ABC', repeat=3)))
# [('A', 'A', 'A'), ('A', 'A', 'B'), ('A', 'A', 'C'), ('A', 'B', 'A'), ('A', 'B', 'B'), ('A', 'B', 'C'), ('A', 'C', 'A'), ('A', 'C', 'B'), ('A', 'C', 'C'), ('B', 'A', 'A'), ('B', 'A', 'B'), ('B', 'A', 'C'), ('B', 'B', 'A'), ('B', 'B', 'B'), ('B', 'B', 'C'), ('B', 'C', 'A'), ('B', 'C', 'B'), ('B', 'C', 'C'), ('C', 'A', 'A'), ('C', 'A', 'B'), ('C', 'A', 'C'), ('C', 'B', 'A'), ('C', 'B', 'B'), ('C', 'B', 'C'), ('C', 'C', 'A'), ('C', 'C', 'B'), ('C', 'C', 'C')]
print(list(product('ABC', 'ABC', 'ABC')))
# [('A', 'A', 'A'), ('A', 'A', 'B'), ('A', 'A', 'C'), ('A', 'B', 'A'), ('A', 'B', 'B'), ('A', 'B', 'C'), ('A', 'C', 'A'), ('A', 'C', 'B'), ('A', 'C', 'C'), ('B', 'A', 'A'), ('B', 'A', 'B'), ('B', 'A', 'C'), ('B', 'B', 'A'), ('B', 'B', 'B'), ('B', 'B', 'C'), ('B', 'C', 'A'), ('B', 'C', 'B'), ('B', 'C', 'C'), ('C', 'A', 'A'), ('C', 'A', 'B'), ('C', 'A', 'C'), ('C', 'B', 'A'), ('C', 'B', 'B'), ('C', 'B', 'C'), ('C', 'C', 'A'), ('C', 'C', 'B'), ('C', 'C', 'C')]
请注意,搜索库函数会迫使您采用与社区使用的词汇一致的词汇。区分以下概念:
- 笛卡尔积,或“替换组合”;
- powerset,或“所有子集的集合”;
- 排列;
- 组合(无需替换);
- 精神错乱;
- 不同的排列(对于有重复的序列);
- 等