假设我有一个清单
die_faces = [1, 2, 3, 4, 5, 6]
。我想生成掷两个骰子的所有 36 种可能结果:(1, 1)
、(1, 2)
、(2, 1)
等。如果我尝试使用 permutations
标准库中的 itertools
:
>>> import itertools
>>> die_faces = [1, 2, 3, 4, 5, 6]
>>> list(itertools.permutations(die_faces, 2))
[(1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 1), (2, 3), (2, 4), (2, 5), (2, 6), (3, 1), (3, 2), (3, 4), (3, 5), (3, 6), (4, 1), (4, 2), (4, 3), (4, 5), (4, 6), (5, 1), (5, 2), (5, 3), (5, 4), (5, 6), (6, 1), (6, 2), (6, 3), (6, 4), (6, 5)]
只有 30 个结果,缺少两个骰子上出现相同数字的结果。看起来它只生成排列而没有重复。我该如何解决这个问题?
您正在寻找 笛卡尔积。
在数学中,笛卡尔积(或积集)是两个集合的直积。
就您而言,这将是
{1, 2, 3, 4, 5, 6}
x {1, 2, 3, 4, 5, 6}
。
itertools
可以帮助你:
import itertools
x = [1, 2, 3, 4, 5, 6]
[p for p in itertools.product(x, repeat=2)]
[(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 1), (2, 2), (2, 3),
(2, 4), (2, 5), (2, 6), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (3, 6),
(4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (4, 6), (5, 1), (5, 2), (5, 3),
(5, 4), (5, 5), (5, 6), (6, 1), (6, 2), (6, 3), (6, 4), (6, 5), (6, 6)]
要获得随机骰子(以完全低效的方式):
import random
random.choice([p for p in itertools.product(x, repeat=2)])
(6, 3)
itertools.combinations_with_replacement
函数:
>>> list(itertools.combinations_with_replacement([1, 2, 3, 4, 5, 6], 2))
[(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 2), (2, 3), (2, 4),
(2, 5), (2, 6), (3, 3), (3, 4), (3, 5), (3, 6), (4, 4), (4, 5), (4, 6),
(5, 5), (5, 6), (6, 6)]
在这种情况下,并不是特别需要列表理解。
给予
import itertools as it
seq = range(1, 7)
r = 2
代码
list(it.product(seq, repeat=r))
详情
显然,笛卡尔积可以生成排列的子集。然而,由此可见:
product
生成所有排列 nr
替换排列,nr
[x for x in it.product(seq, repeat=r)]
无替换的排列,n!
[x for x in it.product(seq, repeat=r) if len(set(x)) == r]
# Equivalent
list(it.permutations(seq, r))
因此,所有组合函数都可以从
product
实现:
combinations_with_replacement
从product
combinations
从permutations
实现,可以通过product
实现(见上文)我想我找到了仅使用
lambdas
、map
和 reduce
的解决方案。
product_function = lambda n: reduce(lambda x, y: x+y, map(lambda i: list(map(lambda j: (i, j), np.arange(n))), np.arange(n)), [])
本质上我正在映射给定一行的第一个 lambda 函数,迭代列
list(map(lambda j: (i, j), np.arange(n)))
然后将其用作新 lambda 函数的输出
lambda i:list(map(lambda j: (i, j), np.arange(n)))
映射到所有可能的行
map(lambda i: list(map(lambda j: (i, j), np.arange(n))), np.arange(m))
然后我们将所有结果列表缩减为一个。
也可以使用两个不同的数字。
prod= lambda n, m: reduce(lambda x, y: x+y, map(lambda i: list(map(lambda j: (i, j), np.arange(m))), np.arange(n)), [])
首先,您需要首先将 itertools.permutations(list) 返回的生成器转换为列表。其次,您可以使用 set() 删除重复项 如下所示:
def permutate(a_list):
import itertools
return set(list(itertools.permutations(a_list)))