我正试图弄清楚如何以递归方式从列表中创建所有可能的n个大小的排列。
例如,n=2
和list=[0,1,5]
的结果为:
[[0, 0], [1, 0], [5, 0], [0, 1], [1, 1], [5, 1], [0, 5], [1, 5], [5, 5]]
或n=3
和list=[2,3]
:
[[2, 2, 2], [3, 2, 2], [2, 3, 2], [3, 3, 2], [2, 2, 3], [3, 2, 3], [2, 3, 3], [3, 3, 3]]
(有点像笛卡尔产品)。
我设法提出了这段代码:
def perm(nlist, m):
if m > len(nlist):
return
if m == 0 or m == len(nlist):
return [[]]
results = []
for list_i in nlist:
temp = list(nlist)
temp.remove(list_i)
results.extend(map(lambda x: [list_i] + x, perm(temp, m-1)))
return results
但它没有像[0,0] [1,1] [2,2]
等那样给出排列。
有人为我提供解决方案吗?
如何在不使用map()
和lambda()
的情况下完成此操作?
答案 0 :(得分:2)
您要查找的结果是Cartesian product,它是所有有序对(a,b)的集合,其中a∈A和b∈B。或者,所有组合的所有排列。
from itertools import combinations_with_replacement as iter_combs
from itertools import permutations
def perms_combs(l, n):
all_combs = []
for l in list(iter_combs(l, n)):
[all_combs.append(perm) for perm in list(permutations(l, n))]
return list(set(all_combs))
>> print list(product([0, 1, 5], repeat=2))
[(0, 0), (0, 0), (0, 1), (1, 0), (0, 5), (5, 0), (1, 1), (1, 1), (1, 5), (5, 1), (5, 5), (5, 5)]
>> print list(product([2, 3], repeat=3))
[(3, 3, 3), (2, 2, 2), (2, 3, 2), (3, 3, 2), (2, 3, 3), (3, 2, 2), (3, 2, 3), (2, 2, 3)]
然而,此过程已由itertools函数涵盖:product
from itertools import product
>> print product([0, 1, 5], 2)
[(0, 0), (0, 0), (0, 1), (1, 0), (0, 5), (5, 0), (1, 1), (1, 1), (1, 5), (5, 1), (5, 5), (5, 5)]
>> print product([2, 3], 3)
[(3, 3, 3), (2, 2, 2), (2, 3, 2), (3, 3, 2), (2, 3, 3), (3, 2, 2), (3, 2, 3), (2, 2, 3)]
答案 1 :(得分:2)
这不像笛卡尔积的那种;它就像<笛卡尔产品一样 。
>>> from itertools import product
>>> list(product([0,1,5], repeat=2))
[(0, 0), (0, 1), (0, 5), (1, 0), (1, 1), (1, 5), (5, 0), (5, 1), (5, 5)]
>>> list(product([2,3], repeat=3))
[(2, 2, 2), (2, 2, 3), (2, 3, 2), (2, 3, 3), (3, 2, 2), (3, 2, 3), (3, 3, 2), (3, 3, 3)]
itertools.product
的polyfill如下:
def product(*args, **kwds):
# product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
# product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
pools = map(tuple, args) * kwds.get('repeat', 1)
result = [[]]
for pool in pools:
result = [x+[y] for x in result for y in pool]
for prod in result:
yield tuple(prod)
但是既然你不能使用itertools,你也可以自由地为你的问题编写一个更有效的解决方案。由于我们只计算n
个相同迭代的乘积,我们只需将其称为笛卡尔指数:
def cartesian_exponent(li, e=1):
pools = [li] * e
result = [[]]
for pool in pools:
result = [x+[y] for x in result for y in pool]
return result
或递归使用另一个难以理解的列表理解:
def cartesian_exponent(li, e=1):
if e == 1:
return [[x] for x in li]
else:
return [[x]+y for x in li for y in cartesian_exponent(li, e=e-1)]
可以将其压缩为一行:
def cartesian_exponent(li, e=1):
return [[x] for x in li] if e == 1 else [[x] + y for x in li for y in cartesian_exponent(li, e=e-1)]
但是那时你会牺牲简洁性的可读性而且这不是bueno。难以理解的列表理解已经不够透明了。
一些测试:
>>> cartesian_exponent([0,1,5], e=2)
[[0, 0], [0, 1], [0, 5], [1, 0], [1, 1], [1, 5], [5, 0], [5, 1], [5, 5]]
>>> cartesian_exponent([2,3], e=3)
[[2, 2, 2], [2, 2, 3], [2, 3, 2], [2, 3, 3], [3, 2, 2], [3, 2, 3], [3, 3, 2], [3, 3, 3]]