Làm thế nào để tạo ra tất cả các hoán vị của một danh sách?


592

Làm thế nào để bạn tạo ra tất cả các hoán vị của một danh sách trong Python, độc lập với loại phần tử trong danh sách đó?

Ví dụ:

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]

5
Tôi đồng ý với câu trả lời đệ quy, được chấp nhận - HÔM NAY. Tuy nhiên, điều này vẫn tồn tại ở đó như là một vấn đề khoa học máy tính lớn. Câu trả lời được chấp nhận giải quyết vấn đề này với độ phức tạp theo cấp số nhân (2 ^ NN = len (danh sách)) Giải quyết nó (hoặc chứng minh bạn không thể) trong thời gian đa thức :) Xem "vấn đề nhân viên bán hàng du lịch"
FlipMcF

38
@FlipMcF Sẽ rất khó để "giải quyết" trong thời gian đa thức, vì phải mất thời gian để thậm chí chỉ liệt kê đầu ra ... vì vậy, không, không thể.
Thomas

Câu trả lời:


489

Bắt đầu với Python 2.6 (và nếu bạn đang dùng Python 3), bạn có một công cụ thư viện chuẩn cho việc này : itertools.permutations.

import itertools
list(itertools.permutations([1, 2, 3]))

Nếu bạn đang sử dụng Python cũ hơn (<2.6) vì một số lý do hoặc chỉ tò mò muốn biết nó hoạt động như thế nào, thì đây là một cách tiếp cận hay, được lấy từ 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:]

Một vài cách tiếp cận khác được liệt kê trong tài liệu của itertools.permutations. Đây là một:

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

Và một cái khác, dựa trên 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)

14
Điều này và các giải pháp đệ quy khác có nguy cơ tiềm ẩn trong việc ăn hết RAM nếu danh sách được hoán vị đủ lớn
Boris Gorelik

3
Họ cũng đạt đến giới hạn đệ quy (và chết) với các danh sách lớn
dbr

58
bgbg, dbr: Nó sử dụng một trình tạo, vì vậy chính chức năng này sẽ không chiếm hết bộ nhớ. Còn lại với bạn về cách tiêu thụ iterator được trả về bởi all_perms (giả sử bạn có thể ghi mỗi lần lặp vào đĩa và không phải lo lắng về bộ nhớ). Tôi biết bài này đã cũ nhưng tôi đang viết bài này vì lợi ích của tất cả những người đọc nó bây giờ. Ngoài ra, cách tốt nhất là sử dụng itertools.permutations () như nhiều người đã chỉ ra.
Jagtesh Chadha

18
Không chỉ là một máy phát điện. Đó là sử dụng các bộ tạo lồng nhau, mà mỗi bộ tạo ra cho bộ trước gọi lên ngăn xếp cuộc gọi, trong trường hợp không rõ ràng. Nó sử dụng bộ nhớ O (n), đó là tốt.
cdunn2001

1
PS: Tôi đã sửa nó, for i in range(len(elements))thay vì for i in range(len(elements)+1). Trong thực tế, phần tử đơn lẻ elements[0:1]có thể ở len(elements)các vị trí khác nhau, trong kết quả, không len(elements)+1.
Eric O Lebigot

339

Và trong Python 2.6 trở đi:

import itertools
itertools.permutations([1,2,3])

(được trả lại dưới dạng trình tạo. Sử dụng list(permutations(l))để trả về dưới dạng danh sách.)


15
Cũng hoạt động trong Python 3
wheleph

10
Lưu ý rằng có tồn tại một rtham số, ví dụ: itertools.permutations([1,2,3], r=2)sẽ tạo ra tất cả các hoán vị có thể chọn 2 phần tử:[(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
toto_tico

278

Đoạn mã sau với Python 2.6 trở lên CHỈ

Đầu tiên, nhập khẩu itertools:

import itertools

Hoán vị (vấn đề đặt hàng):

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

Kết hợp (thứ tự KHÔNG quan trọng):

print list(itertools.combinations('123', 2))
[('1', '2'), ('1', '3'), ('2', '3')]

Sản phẩm của Cartesian (với một số lần lặp):

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

Sản phẩm của Cartesian (với một lần lặp và chính nó):

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

2
+1! Liên kết tài liệu: docs.python.org/2/l Library / itemools.html
Pramod

`danh sách in (itertools.permutations ([1,2,3,4], 2)) ^` SyntaxError: cú pháp không hợp lệ` Chỉ cần bắt đầu sử dụng Mã VS Tôi đã làm gì sai? Con trỏ đang chỉ dưới "t" của "danh sách"
gus

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

gọi là:

permutations('abc')

Tại sao in đuôi và sau đó trả về Không? Tại sao không trả lại đuôi thay thế? Tại sao không trả lại bất cứ điều gì?
bugmenot123

30
#!/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])

Đầu ra:

[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 2, 1]
[3, 1, 2]

Khi tôi hoán đổi nội dung của danh sách, nó yêu cầu một loại trình tự có thể thay đổi làm đầu vào. Ví dụ: perm(list("ball"))sẽ hoạt động và perm("ball")sẽ không vì bạn không thể thay đổi một chuỗi.

Việc triển khai Python này được lấy cảm hứng từ thuật toán được trình bày trong cuốn sách Thuật toán máy tính của Horowitz, Sahni và Rajasekeran .


Tôi giả sử k là độ dài hoặc hoán vị. Cho k = 2 đầu ra [1, 2, 3]. Không nên là (1, 2) (1, 3) (2, 1) (2, 3) (3, 1) (3, 2) ??
Konstantinos Monachopoulos

k là chỉ số của phần tử bạn muốn trao đổi
sf8193

22

Giải pháp này thực hiện một trình tạo, để tránh giữ tất cả các hoán vị trên bộ nhớ:

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

16

Trong một phong cách chức năng

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

Kết quả:

[[0, 1, 2], [1, 0, 2], [1, 2, 0], [0, 2, 1], [2, 0, 1], [2, 1, 0]]

15

Đoạn mã sau là một hoán vị tại chỗ của một danh sách nhất định, được triển khai như một trình tạo. Vì nó chỉ trả về các tham chiếu đến danh sách, danh sách không nên được sửa đổi bên ngoài trình tạo. Giải pháp là không đệ quy, vì vậy sử dụng bộ nhớ thấp. Hoạt động tốt với nhiều bản sao của các yếu tố trong danh sách đầu vào.

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

15

Một cách khá rõ ràng theo ý kiến ​​của tôi cũng có thể là:

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

11
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

Đầu ra:

[
    [1, 2.0, 'three'], 
    [1, 'three', 2.0], 
    [2.0, 1, 'three'], 
    [2.0, 'three', 1], 
    ['three', 1, 2.0], 
    ['three', 2.0, 1]
]

2
Mặc dù về mặt kỹ thuật nó tạo ra đầu ra mong muốn, bạn đang giải quyết một cái gì đó có thể là O (n lg n) trong O (n ^ n) - "hơi" không hiệu quả đối với các bộ lớn.
James

3
@James: Tôi hơi bối rối bởi O (n log n) mà bạn đưa ra: số lượng hoán vị là n!, Vốn đã lớn hơn nhiều so với O (n log n); vì vậy, tôi không thể thấy làm thế nào một giải pháp có thể là O (n log n). Tuy nhiên, sự thật là giải pháp này nằm trong O (n ^ n), lớn hơn nhiều so với n!, Rõ ràng từ phép tính gần đúng của Stirling.
Eric O Lebigot

9

Tôi đã sử dụng một thuật toán dựa trên hệ thống số giai thừa - Đối với danh sách độ dài n, bạn có thể lắp ráp từng mục hoán vị theo mục, chọn từ các mục còn lại ở mỗi giai đoạn. Bạn có n lựa chọn cho mục đầu tiên, n-1 cho mục thứ hai và chỉ có một lựa chọn cho mục cuối cùng, vì vậy bạn có thể sử dụng các chữ số của một số trong hệ thống số giai thừa làm chỉ số. Bằng cách này, các số từ 0 đến n! -1 tương ứng với tất cả các hoán vị có thể có theo thứ tự từ điển.

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

đầu ra:

[[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]]

Phương pháp này không đệ quy, nhưng máy tính của tôi chậm hơn một chút và xrange gây ra lỗi khi n! quá lớn để được chuyển đổi thành số nguyên dài C (n = 13 đối với tôi). Nó là đủ khi tôi cần nó, nhưng nó không phải là itertools.permutations bởi một cú sút xa.


3
Xin chào, chào mừng bạn đến với Stack Overflow. Mặc dù việc đăng phương pháp vũ phu có giá trị của nó, nhưng nếu bạn không nghĩ giải pháp của mình tốt hơn giải pháp được chấp nhận, có lẽ bạn không nên đăng nó (đặc biệt là về một câu hỏi cũ đã có quá nhiều câu trả lời).
Hannele

1
Tôi thực sự đang tìm kiếm một cách tiếp cận phi thư viện vũ phu, vì vậy cảm ơn!
Jay Taylor

8

Lưu ý rằng thuật toán này có n factorialđộ phức tạp về thời gian, trong đó nđộ dài của danh sách đầu vào

In kết quả khi đang chạy:

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

Thí dụ:

permutation([1,2,3])

Đầu ra:

[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]

8

Người ta thực sự có thể lặp lại qua phần tử đầu tiên của mỗi hoán vị, như trong câu trả lời của tzwenn. Tuy nhiên, hiệu quả hơn là viết giải pháp này theo cách này:

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

Giải pháp này nhanh hơn khoảng 30%, rõ ràng là nhờ vào đệ quy kết thúc len(elements) <= 1thay vì 0. Nó cũng hiệu quả hơn về bộ nhớ, vì nó sử dụng chức năng tạo (thông qua yield), giống như trong giải pháp của Riccardo Reyes.


6

Điều này được lấy cảm hứng từ việc triển khai Haskell bằng cách hiểu danh sách:

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

6

Thực hiện thường xuyên (không có năng suất - sẽ làm mọi thứ trong bộ nhớ):

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

Năng suất thực hiện:

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]

Ý tưởng cơ bản là đi qua tất cả các phần tử trong mảng cho vị trí thứ nhất, và sau đó ở vị trí thứ 2 sẽ chuyển qua tất cả các phần tử còn lại mà không có phần tử được chọn cho phần 1, v.v. Bạn có thể thực hiện điều này với đệ quy , trong đó tiêu chí dừng là nhận được một mảng gồm 1 phần tử - trong trường hợp đó bạn trả về mảng đó.

nhập mô tả hình ảnh ở đây


Điều này không hoạt động đối với tôi _> ValueError: toán hạng không thể được phát cùng với hình dạng (0,) (2,) , cho dòng này:perms = getPermutations(array[:i] + array[i+1:])
RK1

@ RK1 đầu vào là gì?
David Refaeli

Tôi đang đi qua một numpymảng _> getPermutations(np.array([1, 2, 3])), tôi thấy nó hoạt động cho một danh sách, chỉ bị nhầm lẫn là func arg là array:)
RK1

@ RK1 rất vui vì nó hoạt động: danh sách-) là một từ khóa trong python, vì vậy thường không nên gọi tham số của bạn là từ khóa, vì nó sẽ "phủ bóng" nó. Vì vậy, tôi sử dụng mảng từ, vì đây là chức năng thực tế của danh sách mà tôi đang sử dụng - mảng giống như cách của họ. Tôi đoán nếu tôi sẽ viết tài liệu tôi sẽ làm rõ nó. Ngoài ra tôi tin rằng các câu hỏi "phỏng vấn" cơ bản nên được giải quyết mà không cần các gói bên ngoài, như numpy.
David Refaeli

Haha đó là sự thật, yeah đã cố gắng sử dụng nó numbavà tham lam với tốc độ nên đã cố gắng sử dụng nó độc quyền với numpymảng
RK1

4

Đối với hiệu suất, một giải pháp gọn gàng lấy cảm hứng từ Knuth , (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, :]

Sao chép khối lớn bộ nhớ giúp tiết kiệm thời gian - nhanh hơn 20 lần so với list(itertools.permutations(range(n)):

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

3
from __future__ import print_function

def perm(n):
    p = []
    for i in range(0,n+1):
        p.append(i)
    while True:
        for i in range(1,n+1):
            print(p[i], end=' ')
        print("")
        i = n - 1
        found = 0
        while (not found and i>0):
            if p[i]<p[i+1]:
                found = 1
            else:
                i = i - 1
        k = n
        while p[i]>p[k]:
            k = k - 1
        aux = p[i]
        p[i] = p[k]
        p[k] = aux
        for j in range(1,(n-i)/2+1):
            aux = p[i+j]
            p[i+j] = p[n-j+1]
            p[n-j+1] = aux
        if not found:
            break

perm(5)

3

Đây là một thuật toán hoạt động trên một danh sách mà không tạo các danh sách trung gian mới tương tự như giải pháp của Ber tại https://stackoverflow.com/a/108651/184528 .

def permute(xs, low=0):
    if low + 1 >= len(xs):
        yield xs
    else:
        for p in permute(xs, low + 1):
            yield p        
        for i in range(low + 1, len(xs)):        
            xs[low], xs[i] = xs[i], xs[low]
            for p in permute(xs, low + 1):
                yield p        
            xs[low], xs[i] = xs[i], xs[low]

for p in permute([1, 2, 3, 4]):
    print p

Bạn có thể tự mình thử mã ở đây: http://repl.it/J9v


3

Vẻ đẹp của đệ quy:

>>> import copy
>>> def perm(prefix,rest):
...      for e in rest:
...              new_rest=copy.copy(rest)
...              new_prefix=copy.copy(prefix)
...              new_prefix.append(e)
...              new_rest.remove(e)
...              if len(new_rest) == 0:
...                      print new_prefix + new_rest
...                      continue
...              perm(new_prefix,new_rest)
... 
>>> perm([],['a','b','c','d'])
['a', 'b', 'c', 'd']
['a', 'b', 'd', 'c']
['a', 'c', 'b', 'd']
['a', 'c', 'd', 'b']
['a', 'd', 'b', 'c']
['a', 'd', 'c', 'b']
['b', 'a', 'c', 'd']
['b', 'a', 'd', 'c']
['b', 'c', 'a', 'd']
['b', 'c', 'd', 'a']
['b', 'd', 'a', 'c']
['b', 'd', 'c', 'a']
['c', 'a', 'b', 'd']
['c', 'a', 'd', 'b']
['c', 'b', 'a', 'd']
['c', 'b', 'd', 'a']
['c', 'd', 'a', 'b']
['c', 'd', 'b', 'a']
['d', 'a', 'b', 'c']
['d', 'a', 'c', 'b']
['d', 'b', 'a', 'c']
['d', 'b', 'c', 'a']
['d', 'c', 'a', 'b']
['d', 'c', 'b', 'a']

3

Thuật toán này là thuật toán hiệu quả nhất, nó tránh được việc truyền mảng và thao tác trong các cuộc gọi đệ quy, hoạt động trong Python 2, 3:

def permute(items):
    length = len(items)
    def inner(ix=[]):
        do_yield = len(ix) == length - 1
        for i in range(0, length):
            if i in ix: #avoid duplicates
                continue
            if do_yield:
                yield tuple([items[y] for y in ix + [i]])
            else:
                for p in inner(ix + [i]):
                    yield p
    return inner()

Sử dụng:

for p in permute((1,2,3)):
    print(p)

(1, 2, 3)
(1, 3, 2)
(2, 1, 3)
(2, 3, 1)
(3, 1, 2)
(3, 2, 1)

3
def pzip(c, seq):
    result = []
    for item in seq:
        for i in range(len(item)+1):
            result.append(item[i:]+c+item[:i])
    return result


def perm(line):
    seq = [c for c in line]
    if len(seq) <=1 :
        return seq
    else:
        return pzip(seq[0], perm(seq[1:]))

3

TIẾP CẬN KHÁC (không có libs)

def permutation(input):
    if len(input) == 1:
        return input if isinstance(input, list) else [input]

    result = []
    for i in range(len(input)):
        first = input[i]
        rest = input[:i] + input[i + 1:]
        rest_permutation = permutation(rest)
        for p in rest_permutation:
            result.append(first + p)
    return result

Đầu vào có thể là một chuỗi hoặc một danh sách

print(permutation('abcd'))
print(permutation(['a', 'b', 'c', 'd']))

Điều này không làm việc cho một danh sách với số nguyên, ví dụ. [1, 2, 3]trả về[6, 6, 6, 6, 6, 6]
RK1

@ RK1, bạn có thể thử cái nàyprint(permutation(['1','2','3']))
Tatsu

Cảm ơn đã hoạt động
RK1

3

Disclaimer: cắm hình dạng của tác giả gói. :)

Các Trotter gói là khác biệt so với hầu hết các trường ở chỗ nó tạo ra danh sách giả không thực sự chứa hoán vị nhưng thay vì mô tả các ánh xạ giữa hoán vị và vị trí tương ứng trong một trật tự, làm cho nó có thể làm việc với 'danh sách' rất lớn các hoán vị, như thể hiện trong bản demo này thực hiện các thao tác tức thời và tra cứu trong một danh sách giả 'chứa' tất cả các hoán vị của các chữ cái trong bảng chữ cái, mà không sử dụng nhiều bộ nhớ hoặc xử lý hơn một trang web thông thường.

Trong mọi trường hợp, để tạo danh sách hoán vị, chúng ta có thể làm như sau.

import trotter

my_permutations = trotter.Permutations(3, [1, 2, 3])

print(my_permutations)

for p in my_permutations:
    print(p)

Đầu ra:

Một danh sách giả chứa 6 3 hoán vị của [1, 2, 3].
[1, 2, 3]
[1, 3, 2]
[3, 1, 2]
[3, 2, 1]
[2, 3, 1]
[2, 1, 3]

2

Tạo tất cả các hoán vị có thể

Tôi đang sử dụng python3.4:

def calcperm(arr, size):
    result = set([()])
    for dummy_idx in range(size):
        temp = set()
        for dummy_lst in result:
            for dummy_outcome in arr:
                if dummy_outcome not in dummy_lst:
                    new_seq = list(dummy_lst)
                    new_seq.append(dummy_outcome)
                    temp.add(tuple(new_seq))
        result = temp
    return result

Các trường hợp thử nghiệm:

lst = [1, 2, 3, 4]
#lst = ["yellow", "magenta", "white", "blue"]
seq = 2
final = calcperm(lst, seq)
print(len(final))
print(final)

2

Để tiết kiệm cho bạn hàng giờ có thể tìm kiếm và thử nghiệm, đây là giải pháp hoán vị không đệ quy trong Python cũng hoạt động với Numba (kể từ câu 0.41):

@numba.njit()
def permutations(A, k):
    r = [[i for i in range(0)]]
    for i in range(k):
        r = [[a] + b for a in A for b in r if (a in b)==False]
    return r
permutations([1,2,3],3)
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]

Để tạo ấn tượng về hiệu suất:

%timeit permutations(np.arange(5),5)

243 µs ± 11.1 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
time: 406 ms

%timeit list(itertools.permutations(np.arange(5),5))
15.9 µs ± 8.61 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
time: 12.9 s

Vì vậy, chỉ sử dụng phiên bản này nếu bạn phải gọi nó từ chức năng njited, nếu không thích thực hiện itertools.


1

Tôi thấy rất nhiều phép lặp đang diễn ra bên trong các hàm đệ quy này, không chính xác đệ quy thuần túy ...

Vì vậy, đối với những người bạn không thể tuân theo một vòng lặp duy nhất, đây là một giải pháp đệ quy đầy đủ, hoàn toàn không cần thiết

def all_insert(x, e, i=0):
    return [x[0:i]+[e]+x[i:]] + all_insert(x,e,i+1) if i<len(x)+1 else []

def for_each(X, e):
    return all_insert(X[0], e) + for_each(X[1:],e) if X else []

def permute(x):
    return [x] if len(x) < 2 else for_each( permute(x[1:]) , x[0])


perms = permute([1,2,3])

1

Giải pháp khác:

def permutation(flag, k =1 ):
    N = len(flag)
    for i in xrange(0, N):
        if flag[i] != 0:
            continue
        flag[i] = k 
        if k == N:
            print flag
        permutation(flag, k+1)
        flag[i] = 0

permutation([0, 0, 0])

0

Giải pháp Python của tôi:

def permutes(input,offset):
    if( len(input) == offset ):
        return [''.join(input)]

    result=[]        
    for i in range( offset, len(input) ):
         input[offset], input[i] = input[i], input[offset]
         result = result + permutes(input,offset+1)
         input[offset], input[i] = input[i], input[offset]
    return result

# input is a "string"
# return value is a list of strings
def permutations(input):
    return permutes( list(input), 0 )

# Main Program
print( permutations("wxyz") )

0
def permutation(word, first_char=None):
    if word == None or len(word) == 0: return []
    if len(word) == 1: return [word]

    result = []
    first_char = word[0]
    for sub_word in permutation(word[1:], first_char):
        result += insert(first_char, sub_word)
    return sorted(result)

def insert(ch, sub_word):
    arr = [ch + sub_word]
    for i in range(len(sub_word)):
        arr.append(sub_word[i:] + ch + sub_word[:i])
    return arr


assert permutation(None) == []
assert permutation('') == []
assert permutation('1')  == ['1']
assert permutation('12') == ['12', '21']

print permutation('abc')

Đầu ra: ['abc', 'acb', 'bac', 'bca', 'cab', 'cba']


0

Sử dụng Counter

from collections import Counter

def permutations(nums):
    ans = [[]]
    cache = Counter(nums)

    for idx, x in enumerate(nums):
        result = []
        for items in ans:
            cache1 = Counter(items)
            for id, n in enumerate(nums):
                if cache[n] != cache1[n] and items + [n] not in result:
                    result.append(items + [n])

        ans = result
    return ans
permutations([1, 2, 2])
> [[1, 2, 2], [2, 1, 2], [2, 2, 1]]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.