Ric*_*yes 543 python algorithm permutation combinatorics python-2.5
如何在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]
Run Code Online (Sandbox Code Playgroud)
Eli*_*sky 436
从Python 2.6开始(如果您使用的是Python 3),您可以使用标准库工具:itertools.permutations.
import itertools
list(itertools.permutations([1, 2, 3]))
Run Code Online (Sandbox Code Playgroud)
如果您出于某种原因使用较旧的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:]
Run Code Online (Sandbox Code Playgroud)
文档中列出了几种替代方法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
Run Code Online (Sandbox Code Playgroud)
另一个基于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)
Run Code Online (Sandbox Code Playgroud)
Bri*_*ian 330
在Python 2.6以后:
import itertools
itertools.permutations([1,2,3])
Run Code Online (Sandbox Code Playgroud)
(作为生成器返回.用于list(permutations(l))作为列表返回.)
e-s*_*tis 264
以下代码仅适用于Python 2.6及更高版本
一,进口itertools:
import itertools
Run Code Online (Sandbox Code Playgroud)
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)]
Run Code Online (Sandbox Code Playgroud)
print list(itertools.combinations('123', 2))
[('1', '2'), ('1', '3'), ('2', '3')]
Run Code Online (Sandbox Code Playgroud)
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)]
Run Code Online (Sandbox Code Playgroud)
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)]
Run Code Online (Sandbox Code Playgroud)
小智 37
def permutations(head, tail=''):
if len(head) == 0: print tail
else:
for i in range(len(head)):
permutations(head[0:i] + head[i+1:], tail+head[i])
Run Code Online (Sandbox Code Playgroud)
称为:
permutations('abc')
Run Code Online (Sandbox Code Playgroud)
小智 25
#!/usr/bin/env python
def perm(a, k=0):
if k == len(a):
print a
else:
for i in xrange(k, len(a)):
a[k], a[i] = a[i] ,a[k]
perm(a, k+1)
a[k], a[i] = a[i], a[k]
perm([1,2,3])
Run Code Online (Sandbox Code Playgroud)
输出:
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 2, 1]
[3, 1, 2]
Run Code Online (Sandbox Code Playgroud)
当我交换列表的内容时,需要一个可变序列类型作为输入.例如perm(list("ball")),perm("ball")因为你不能改变字符串,所以不会工作.
这个Python实现的灵感来自Horowitz,Sahni和Rajasekeran的计算机算法一书中提出的算法.
Ric*_*yes 21
此解决方案实现了一个生成器,以避免在内存中保留所有排列:
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
Run Code Online (Sandbox Code Playgroud)
Ber*_*Ber 15
以下代码是给定列表的就地排列,实现为生成器.由于它只返回对列表的引用,因此不应在生成器外修改列表.解决方案是非递归的,因此使用低内存.在输入列表中也可以使用多个元素副本.
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
Run Code Online (Sandbox Code Playgroud)
小智 13
在我看来,一个非常明显的方式可能是:
def permutList(l):
if not l:
return [[]]
res = []
for e in l:
temp = l[:]
temp.remove(e)
res.extend([[e] + r for r in permutList(temp)])
return res
Run Code Online (Sandbox Code Playgroud)
小智 12
在功能风格
def addperm(x,l):
return [ l[0:i] + [x] + l[i:] for i in range(len(l)+1) ]
def perm(l):
if len(l) == 0:
return [[]]
return [x for y in perm(l[1:]) for x in addperm(l[0],y) ]
print perm([ i for i in range(3)])
Run Code Online (Sandbox Code Playgroud)
结果:
[[0, 1, 2], [1, 0, 2], [1, 2, 0], [0, 2, 1], [2, 0, 1], [2, 1, 0]]
Run Code Online (Sandbox Code Playgroud)
zmk*_*zmk 10
list2Perm = [1, 2.0, 'three']
listPerm = [[a, b, c]
for a in list2Perm
for b in list2Perm
for c in list2Perm
if ( a != b and b != c and a != c )
]
print listPerm
Run Code Online (Sandbox Code Playgroud)
输出:
[
[1, 2.0, 'three'],
[1, 'three', 2.0],
[2.0, 1, 'three'],
[2.0, 'three', 1],
['three', 1, 2.0],
['three', 2.0, 1]
]
Run Code Online (Sandbox Code Playgroud)
Dav*_*eli 10
常规实现(无产量 - 将在内存中执行所有操作):
def getPermutations(array):
if len(array) == 1:
return [array]
permutations = []
for i in range(len(array)):
# get all perm's of subarray w/o current item
perms = getPermutations(array[:i] + array[i+1:])
for p in perms:
permutations.append([array[i], *p])
return permutations
Run Code Online (Sandbox Code Playgroud)
产量实施:
def getPermutations(array):
if len(array) == 1:
yield array
else:
for i in range(len(array)):
perms = getPermutations(array[:i] + array[i+1:])
for p in perms:
yield [array[i], *p]
Run Code Online (Sandbox Code Playgroud)
基本思想是遍历数组中第 1 个位置的所有元素,然后在第 2 个位置遍历所有其余元素,而没有为第一个选择的元素,依此类推。您可以使用recursion来做到这一点,其中停止条件正在获取一个包含 1 个元素的数组 - 在这种情况下,您将返回该数组。
小智 8
我使用了基于阶乘数系统的算法- 对于长度为n的列表,您可以按项目组合每个排列项目,从每个阶段的左侧项目中进行选择.第一项有n个选择,第二个项有n-1,最后一个只有一个,所以你可以使用阶乘数系统中数字的数字作为索引.这样,数字0到n!-1对应于字典顺序中的所有可能的排列.
from math import factorial
def permutations(l):
permutations=[]
length=len(l)
for x in xrange(factorial(length)):
available=list(l)
newPermutation=[]
for radix in xrange(length, 0, -1):
placeValue=factorial(radix-1)
index=x/placeValue
newPermutation.append(available.pop(index))
x-=index*placeValue
permutations.append(newPermutation)
return permutations
permutations(range(3))
Run Code Online (Sandbox Code Playgroud)
输出:
[[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]]
Run Code Online (Sandbox Code Playgroud)
这个方法是非递归的,但它在我的计算机上稍慢,xrange在n时引发错误!太大而无法转换为C长整数(对我来说n = 13).当我需要它时它已经足够了,但它不是一个很长的镜头的itertools.permutations.
人们确实可以迭代每个排列的第一个元素,如tzwenn的答案; 我更喜欢用这种方式编写这个解决方案:
def all_perms(elements):
if len(elements) <= 1:
yield elements # Only permutation possible = no permutation
else:
# Iteration over the first element in the result permutation:
for (index, first_elmt) in enumerate(elements):
other_elmts = elements[:index]+elements[index+1:]
for permutation in all_perms(other_elmts):
yield [first_elmt] + permutation
Run Code Online (Sandbox Code Playgroud)
这个解决方案快了大约30%,显然是由于递归结束len(elements) <= 1而不是0.它还具有更高的内存效率,因为它使用生成器函数(通过yield),就像Riccardo Reyes的解决方案一样.
请注意,此算法具有n factorial时间复杂度,其中n是输入列表的长度
在运行中打印结果:
global result
result = []
def permutation(li):
if li == [] or li == None:
return
if len(li) == 1:
result.append(li[0])
print result
result.pop()
return
for i in range(0,len(li)):
result.append(li[i])
permutation(li[:i] + li[i+1:])
result.pop()
Run Code Online (Sandbox Code Playgroud)
例:
permutation([1,2,3])
Run Code Online (Sandbox Code Playgroud)
输出:
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
Run Code Online (Sandbox Code Playgroud)
对于性能,一个受Knuth启发的 numpy 解决方案,(p22):
from numpy import empty, uint8
from math import factorial
def perms(n):
f = 1
p = empty((2*n-1, factorial(n)), uint8)
for i in range(n):
p[i, :f] = i
p[i+1:2*i+1, :f] = p[:i, :f] # constitution de blocs
for j in range(i):
p[:i+1, f*(j+1):f*(j+2)] = p[j+1:j+i+2, :f] # copie de blocs
f = f*(i+1)
return p[:n, :]
Run Code Online (Sandbox Code Playgroud)
复制大块内存可以节省时间 - 它比list(itertools.permutations(range(n))以下方法快 20 倍:
In [1]: %timeit -n10 list(permutations(range(10)))
10 loops, best of 3: 815 ms per loop
In [2]: %timeit -n100 perms(10)
100 loops, best of 3: 40 ms per loop
Run Code Online (Sandbox Code Playgroud)
这是受使用列表理解的Haskell实现的启发:
def permutation(list):
if len(list) == 0:
return [[]]
else:
return [[x] + ys for x in list for ys in permutation(delete(list, x))]
def delete(list, item):
lc = list[:]
lc.remove(item)
return lc
Run Code Online (Sandbox Code Playgroud)
免责声明:包作者的无形插头。:)
该猪手包是从大多数实现不同,它产生不实际包含的排列,而是描述的排列和各位置之间的映射关系的顺序,使其能够工作,排列非常大名单“,如图所示伪名单在这个演示中,它在一个“包含”字母表中所有字母排列的伪列表中执行非常即时的操作和查找,而不使用比典型网页更多的内存或处理。
无论如何,要生成排列列表,我们可以执行以下操作。
import trotter
my_permutations = trotter.Permutations(3, [1, 2, 3])
print(my_permutations)
for p in my_permutations:
print(p)
Run Code Online (Sandbox Code Playgroud)
输出:
包含 [1, 2, 3] 的 6 个 3 排列的伪列表。 [1, 2, 3] [1, 3, 2] [3, 1, 2] [3, 2, 1] [2, 3, 1] [2, 1, 3]
如果您不想使用内置方法,例如:
import itertools
list(itertools.permutations([1, 2, 3]))
Run Code Online (Sandbox Code Playgroud)
你可以自己实现排列函数
from collections.abc import Iterable
def permute(iterable: Iterable[str]) -> set[str]:
perms = set()
if len(iterable) == 1:
return {*iterable}
for index, char in enumerate(iterable):
perms.update([char + perm for perm in permute(iterable[:index] + iterable[index + 1:])])
return perms
if __name__ == '__main__':
print(permute('abc'))
# {'bca', 'abc', 'cab', 'acb', 'cba', 'bac'}
print(permute(['1', '2', '3']))
# {'123', '312', '132', '321', '213', '231'}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
575869 次 |
| 最近记录: |