2015-04-30 92 views
2

我想弄清楚如何递归地从列表中创建所有可能的n个大小的排列。如何在Python中递归排列列表中的n个元素?

。例如n=2list=[0,1,5]结果将是:

[[0, 0], [1, 0], [5, 0], [0, 1], [1, 1], [5, 1], [0, 5], [1, 5], [5, 5]] 

n=3list=[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()

+1

提示:不要使用'list'作为名字,它是一个[内置函数(https://docs.python.org/3/library/ functions.html#FUNC列表)。 –

+0

你有没有考虑过使用[itertools.permutations](https://docs.python.org/2/library/itertools.html#itertools.permutations)? –

+0

[如何在Python中生成列表的所有排列]可能的重复(http://stackoverflow.com/questions/104420/how-to-generate-all-permutations-of-a-list-in-python) –

回答

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如下:

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相同iterables的产品,就让我们把它叫做笛卡尔指数:

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]] 
+0

我喜欢它的简单,但即时寻找一个递归解决方案。 thx –

+0

@runtuchman递归解决方案已添加到我的答案。 – Shashank

+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)] 
相关问题