如何在Python中生成列表的所有排列
时间:2020-03-06 14:27:18 来源:igfitidea点击:
如何在Python中生成列表的所有排列,而与列表中元素的类型无关?
例如:
permutations([]) [] permutations([1]) [1] permutations([1, 2]) [1, 2] [2, 1] permutations([1, 2, 3]) [1, 2, 3] [1, 3, 2] [2, 1, 3] [2, 3, 1] [3, 1, 2] [3, 2, 1]
解决方案
此解决方案实现了一个生成器,以避免将所有排列保留在内存中:
def permutations (orig_list):
if not isinstance(orig_list, list):
orig_list = list(orig_list)
yield orig_list
if len(orig_list) == 1:
return
for n in sorted(orig_list):
new_list = orig_list[:]
pos = new_list.index(n)
del(new_list[pos])
new_list.insert(0, n)
for resto in permutations(new_list[1:]):
if new_list[:1] + resto <> orig_list:
yield new_list[:1] + resto
从Python 2.6开始(如果我们使用的是Python 3),我们可以使用一个标准库工具:itertools.permutations。
import itertools list(itertools.permutations([1, 2, 3]))
如果我们出于某种原因使用旧版Python(<2.6),或者只是想知道它的工作原理,那么这是一种不错的方法,该方法取自http://code.activestate.com/recipes/252178/:
def all_perms(elements):
if len(elements) <=1:
yield elements
else:
for perm in all_perms(elements[1:]):
for i in range(len(elements)):
# nb elements[0:1] works in both string and list contexts
yield perm[:i] + elements[0:1] + perm[i:]
itertools.permutations`的文档中列出了几种其他方法。这是一个:
def permutations(iterable, r=None):
# permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC
# permutations(range(3)) --> 012 021 102 120 201 210
pool = tuple(iterable)
n = len(pool)
r = n if r is None else r
if r > n:
return
indices = range(n)
cycles = range(n, n-r, -1)
yield tuple(pool[i] for i in indices[:r])
while n:
for i in reversed(range(r)):
cycles[i] -= 1
if cycles[i] == 0:
indices[i:] = indices[i+1:] + indices[i:i+1]
cycles[i] = n - i
else:
j = cycles[i]
indices[i], indices[-j] = indices[-j], indices[i]
yield tuple(pool[i] for i in indices[:r])
break
else:
return
另一个基于itertools.product:
def permutations(iterable, r=None):
pool = tuple(iterable)
n = len(pool)
r = n if r is None else r
for indices in product(range(n), repeat=r):
if len(set(indices)) == r:
yield tuple(pool[i] for i in indices)
在Python 2.6及更高版本中:
import itertools itertools.permutations([1,2,3])
(作为生成器返回。使用list(permutations(l))作为列表返回。)
原谅我的python文盲,因为我不会在python中提供解决方案。
由于我不知道python 2.6使用哪种方法来生成排列,而eliben的方法看起来像Johnson-Trotter排列生成,因此我们可能会寻找文章
在Wikipedia上的Permutations及其生成中,看起来很像Myrvold和Ruskey在论文中提出的非排序功能。
在我看来,这可以与其他答复中所述的方式在生成器中使用,以大大减少内存需求。请记住,排列不会按字典顺序排列。
以下代码是给定列表的就地排列,实现为生成器。由于仅返回对列表的引用,因此不应在生成器外部修改列表。
解决方案是非递归的,因此使用低内存。输入列表中的元素的多个副本也可以很好地工作。
def permute_in_place(a):
a.sort()
yield list(a)
if len(a) <= 1:
return
first = 0
last = len(a)
while 1:
i = last - 1
while 1:
i = i - 1
if a[i] < a[i+1]:
j = last - 1
while not (a[i] < a[j]):
j = j - 1
a[i], a[j] = a[j], a[i] # swap the values
r = a[i+1:last]
r.reverse()
a[i+1:last] = r
yield list(a)
break
if i == first:
a.reverse()
return
if __name__ == '__main__':
for n in range(5):
for a in permute_in_place(range(1, n+1)):
print a
print
for a in permute_in_place([0, 0, 1, 1, 1]):
print a
print
以下代码仅适用于Python 2.6及更高版本
首先,导入itertools:
import itertools
排列(顺序很重要):
print list(itertools.permutations([1,2,3,4], 2)) [(1, 2), (1, 3), (1, 4), (2, 1), (2, 3), (2, 4), (3, 1), (3, 2), (3, 4), (4, 1), (4, 2), (4, 3)]
组合(顺序无关紧要):
print list(itertools.combinations('123', 2))
[('1', '2'), ('1', '3'), ('2', '3')]
笛卡尔积(具有多个可迭代项):
print list(itertools.product([1,2,3], [4,5,6])) [(1, 4), (1, 5), (1, 6), (2, 4), (2, 5), (2, 6), (3, 4), (3, 5), (3, 6)]
笛卡尔积(本身具有一个可迭代的):
print list(itertools.product([1,2], repeat=3)) [(1, 1, 1), (1, 1, 2), (1, 2, 1), (1, 2, 2), (2, 1, 1), (2, 1, 2), (2, 2, 1), (2, 2, 2)]

