通过重复生成排列

我了解 itertools,但它似乎只能生成不重复的排列。

例如,我想为2个骰子生成所有可能的骰子卷。所以我需要所有大小为2的排列[1,2,3,4,5,6] ,包括重复: (1,1) ,(1,2) ,(2,1) ... 等等

如果可能的话,我不想从头开始实现它

105178 次浏览

你要找的是 笛卡儿积

在数学中,一个笛卡儿积(或乘积集合)是两个集合的直积。

在你的例子中,这是 {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)

你不需要排列,你需要的是 笛卡儿积:

from itertools import product
for roll in product([1, 2, 3, 4, 5, 6], repeat = 2):
print(roll)

在 python 2.7和3.1中有一个 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)]

首先,您需要首先将 itertools.permutations (list)返回的生成器转换为一个列表。然后,可以使用 set ()删除重复项 下面是这样的:

def permutate(a_list):
import itertools
return set(list(itertools.permutations(a_list)))

在这种情况下,并不特别需要列表内涵。

Given

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实现:

我想我找到了一个解决方案,只使用 lambdasmapreduce

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))

然后我们将产生的所有列表归纳为一个。

甚至更好

Can also use two different numbers.

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)), [])