Bir listenin tüm permütasyonları nasıl oluşturulur?


592

Bu listedeki öğelerin türünden bağımsız olarak Python'daki bir listenin tüm permütasyonlarını nasıl üretiyorsunuz?

Örneğin:

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
Tekrarlanan, kabul edilen cevaba katılıyorum - BUGÜN. Ancak, bu hala büyük bir bilgisayar bilimi sorunu olarak ortaya çıkıyor. Kabul edilen cevap bu sorunu üstel karmaşıklıkla çözer (2 ^ NN = len (liste)) Polinom zamanda çözün (veya yapamayacağınızı kanıtlayın) - "Gezgin satıcı sorunu" konusuna bakın
saatinde FlipMcF

37
@FlipMcF Sadece çıktıyı numaralandırmak bile faktöriyel zaman alırsa, polinom zamanda "çözmek" zor olacaktır ... yani, hayır, bu mümkün değil.
Thomas

Yanıtlar:


488

Python 2.6 ile başlayarak (eğer Python 3 iseniz ve) Bir var standart kütüphane bu aracı: itertools.permutations.

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

Bir kullanıyorsanız eski Python (<2.6) nasıl çalıştığını bilmek nedense ya da sadece merak, burada alınan bir güzel yaklaşım var 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:]

Dokümantasyonunda birkaç alternatif yaklaşım listelenmiştir itertools.permutations. Işte bir tane:

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

Ve bir diğeri, aşağıdakilere dayanarak 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
Bu ve diğer özyinelemeli çözümler, izin verilen liste yeterince büyükse tüm RAM'leri yeme potansiyeli vardır
Boris Gorelik 27:05

3
Ayrıca büyük listelerle özyineleme sınırına ulaşırlar (ve ölürler)
dbr

58
bgbg, dbr: Bir jeneratör kullanıyor, bu yüzden fonksiyonun kendisi hafızayı yemez. All_perms tarafından döndürülen yineleyiciyi nasıl tüketeceğiniz konusunda size bırakılmıştır (her yinelemeyi diske yazabileceğinizi ve bellek konusunda endişelenmeyeceğinizi varsayalım). Bu yazının eski olduğunu biliyorum ama bunu şimdi okuyan herkesin yararına yazıyorum. Ayrıca şimdi, en iyi yol birçok kişi tarafından işaret edildiği gibi itertools.permutations () kullanmak olacaktır.
Jagtesh Chadha

18
Sadece bir jeneratör değil . Net değilse, her biri çağrı yığınında bir öncekine verilen iç içe jeneratörler kullanıyor. O (n) hafızayı kullanır, ki bu iyidir.
cdunn2001

1
PS: Ben for i in range(len(elements))yerine sabitledim for i in range(len(elements)+1). Aslında, tekli eleman , sonuçta değil, farklı pozisyonlarda elements[0:1]olabilir . len(elements)len(elements)+1
Eric O Lebigot

339

Ve Python 2.6'dan itibaren:

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

(jeneratör olarak döndürülür. list(permutations(l))Liste olarak dönmek için kullanın .)


15
Python 3'te de çalışıyor
09:39

10
rÖrneğin itertools.permutations([1,2,3], r=2), 2 öğe seçerek tüm olası permütasyonları oluşturacak bir parametre bulunduğuna dikkat edin :[(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
toto_tico

277

SADECE Python 2.6 ve üstü ile aşağıdaki kod

İlk olarak, içe aktarın itertools:

import itertools

Permütasyon (sipariş önemlidir):

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

Kombinasyon (sipariş önemli değil):

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

Kartezyen ürün (birkaç tekrarlanabilir):

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

Kartezyen ürün (bir tekrarlanabilir ve kendisiyle):

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


`baskı listesi (itertools.permutations ([1,2,3,4], 2)) ^` Sözdizimi Hatası: geçersiz sözdizimi 'VS Kodunu kullanmaya başladım Ne yanlış yaptım? İşaretçi "liste" "t" altında işaret
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])

Olarak adlandırılan:

permutations('abc')

Neden kuyruk yazdırın ve daha sonra Yok döndürün? Neden kuyruk döndürmüyorsun? Neden bir şey iade etmiyorsun?
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])

Çıktı:

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

Listenin içeriğini değiştirirken girdi olarak değiştirilebilir bir dizi türü gerekiyor. Örneğin perm(list("ball"))çalışacak ve çalışmayacak perm("ball")çünkü bir dizeyi değiştiremezsiniz.

Bu Python uygulaması Horowitz, Sahni ve Rajasekeran tarafından Bilgisayar Algoritmaları kitabında sunulan algoritmadan esinlenmiştir .


K'nin uzunluk veya permütasyon olduğunu varsayıyorum. K = 2 çıkış için [1, 2, 3]. Olmamalı mı (1, 2) (1, 3) (2, 1) (2, 3) (3, 1) (3, 2) ??
Konstantinos Monachopoulos

k, değiştirmek istediğiniz öğenin
dizinidir

22

Bu çözüm, bellek üzerindeki tüm permütasyonları tutmaktan kaçınmak için bir jeneratör uygular:

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

İşlevsel bir tarzda

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

Sonuç:

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

15

Aşağıdaki kod, oluşturucu olarak uygulanan belirli bir listenin yerinde permütasyonudur. Yalnızca listeye başvuru döndürdüğünden, liste oluşturucunun dışında değiştirilmemelidir. Çözüm özyinelemeli değildir, bu nedenle düşük bellek kullanır. Giriş listesindeki öğelerin birden fazla kopyasıyla da iyi çalışın.

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

Bence oldukça açık bir yol da olabilir:

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

Çıktı:

[
    [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
Teknik olarak istenen çıktıyı üretirken, O (n ^ n) - büyük setler için "hafif" verimsiz O (n lg n) olabilecek bir şeyi çözüyorsunuz.
James

3
@James: Verdiğiniz O (n log n) ile biraz kafam karıştı: permütasyon sayısı n!, Zaten O (n log n) 'den çok daha fazla; bir çözümün O (n log n) olabileceğini göremiyorum. Bununla birlikte, bu çözeltinin Stirling'in yaklaşımından da anlaşılacağı gibi n! 'Den çok daha büyük olan O (n ^ n) içinde olduğu doğrudur.
Eric O Lebigot

9

Faktöriyel sayı sistemine dayalı bir algoritma kullandım - n uzunluğunun bir listesi için, her bir permütasyon öğesini her aşamada kalan öğelerden birini seçerek bir araya getirebilirsiniz. İlk öğe için n seçeneğiniz, ikincisi için n-1 ve sonuncusu için sadece bir seçeneğiniz vardır, böylece faktöriyel sayı sistemindeki bir sayının rakamlarını endeks olarak kullanabilirsiniz. Bu şekilde, 0 ile n! -1 arasındaki sayılar, sözlükbilim düzenindeki tüm olası permütasyonlara karşılık gelir.

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

çıktı:

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

Bu yöntem özyinelemesizdir, ancak bilgisayarımda biraz daha yavaştır ve xrange n olduğunda bir hata oluşturur! C uzunluğunda bir tam sayıya dönüştürülemeyecek kadar büyük (benim için n = 13). İhtiyacım olduğunda yeterliydi, ama uzun bir atışla itertools.permutations yok.


3
Merhaba, Stack Overflow'a hoş geldiniz. Kaba kuvvet yöntemini göndermenin yararları olsa da, çözümünüzün kabul edilen çözümden daha iyi olduğunu düşünmüyorsanız, muhtemelen göndermemelisiniz (özellikle zaten çok fazla cevabı olan eski bir soruda).
Hannele

1
Aslında kaba kuvvet kütüphanesi olmayan bir yaklaşım arıyordum, bu yüzden teşekkürler!
Jay Taylor

8

Bu algoritmanın n factorialzaman karmaşıklığına sahip olduğunu unutmayın; burada ngiriş listesinin uzunluğu

Sonuçları koşarken yazdırı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()    

Misal:

permutation([1,2,3])

Çıktı:

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

8

Gerçekten, her bir permütasyonun ilk elementi üzerinde, tzwenn'in cevabında olduğu gibi tekrar edilebilir. Ancak bu çözümü şu şekilde yazmak daha verimlidir:

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

Görünüşe göre len(elements) <= 1yerine biten özyineleme sayesinde bu çözüm yaklaşık% 30 daha hızlıdır 0. Ayrıca, yieldRiccardo Reyes'in çözümünde olduğu gibi, bir jeneratör işlevi (içinden ) kullandığı için, bellekte çok daha verimlidir .


6

Bu, liste kavrayışı kullanan Haskell uygulamasından esinlenmiştir:

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

Düzenli uygulama (verim yok - hafızadaki her şeyi yapacak):

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

Getiri uygulaması:

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]

Temel fikir 1 pozisyon için dizideki tüm elemanları üzerinden gitmek ve sonra 2 pozisyonda 1 için seçilen elemanın olmadan elemanların geri kalan her şey üzerinde gitmektir, vb ile yapabilirsiniz özyineleme , stop ölçütleri 1 öğeden oluşan bir diziye ulaşmaktır - bu durumda o diziyi döndürürsünüz.

resim açıklamasını buraya girin


Bu benim için çalışmıyor _> ValueError: işlenenler bu çizgi için şekiller (0,) (2,) ile birlikte yayınlanamadı :perms = getPermutations(array[:i] + array[i+1:])
RK1

@ RK1 girdi neydi?
David Refaeli

Bir numpydizi geçiyorum _> getPermutations(np.array([1, 2, 3])), bir liste için işe yaradığını görüyorum, sadece func arg olduğu gibi kafam karıştı array:)
RK1

@ RK1 işe yaradığına sevindim :-) listesi python'da bir anahtar kelime, bu nedenle parametrenizi bir anahtar kelime olarak adlandırmak genellikle iyi bir fikir değildir, çünkü "gölgeleyecektir". Yani ben dizi dizi, bu benim kullandığım listenin gerçek işlevselliği - dizisi gibi bir şekilde kullanın. Belgeleme yazsaydım açıklığa kavuşturacağım sanırım. Ayrıca temel "röportaj" sorularının numpy gibi harici paketler olmadan çözülmesi gerektiğine inanıyorum.
David Refaeli

Haha bu doğru, evet bunu kullanmaya çalışıyordum numbave hızla açgözlülük aldım, bu yüzden sadece numpydizilerle kullanmaya çalıştım
RK1

4

Performans için, bir numpy çözelti esinlenerek 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, :]

Büyük bellek bloklarını kopyalamak zaman kazandırır - 20 kat daha hızlıdır 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

Https://stackoverflow.com/a/108651/184528 adresindeki Ber'in çözümüne benzer yeni ara listeler oluşturmadan bir listede çalışan bir algoritma .

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

Kodu burada kendiniz deneyebilirsiniz: http://repl.it/J9v


3

Özyinelemenin güzelliği:

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

Bu algoritma en etkili olanıdır, yinelenen çağrılarda dizi geçişi ve manipülasyondan kaçınır, Python 2, 3'te çalışır:

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

Kullanımı:

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

BAŞKA BİR YAKLAŞIM (kütüphanesiz)

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

Giriş bir dize veya bir liste olabilir

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

Bu, tamsayıları olan bir liste için çalışmaz, ör. [1, 2, 3]döner[6, 6, 6, 6, 6, 6]
RK1

@ RK1, bunu deneyebilirsinizprint(permutation(['1','2','3']))
Tatsu

Teşekkürler çalışıyor
RK1

3

Yasal Uyarı: paket yazar tarafından şekilsiz fiş. :)

Paça aslında permütasyon içeren ancak görüldüğü gibi daha ziyade, permütasyon çok büyük 'listeleri' ile çalışmak mümkün hale bir sıralamada permütasyon ve ilgili pozisyonları arasındaki eşleştirmeler tarif yok sözde listeleri oluşturur ki paketi en uygulamalarından farklıdır içinde bu demo hangi gerçekleştirdiği tipik bir web sayfası daha fazla bellek kullanmadan veya işlemeden, alfabedeki tüm harfleri permütasyon 'içeren' sahte listesindeki işlemler ve göz-up oldukça anlık.

Her durumda, bir permütasyon listesi oluşturmak için aşağıdakileri yapabiliriz.

import trotter

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

print(my_permutations)

for p in my_permutations:
    print(p)

Çıktı:

6 1 permütasyon [1, 2, 3] içeren bir sahte liste.
[1, 2, 3]
[1, 3, 2]
[3, 1, 2]
[3, 2, 1]
[2, 3, 1]
[2, 1, 3]

2

Tüm olası permütasyonları üretin

Python3.4 kullanıyorum:

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

Test Durumları:

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

2

Sizi olası arama ve deneme saatlerinden kurtarmak için, Python'da Numba ile de çalışan özyinelemesiz permütasyonlar çözümü (v. 0.41'den itibaren):

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

Performans hakkında bir izlenim vermek için:

%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

Bu nedenle, yalnızca njitted işlevinden çağırmanız gerekiyorsa bu sürümü kullanın, aksi takdirde itertools uygulamasını tercih edin.


1

Bu özyinelemeli fonksiyonların içinde çok fazla yineleme görüyorum , tam olarak saf değil özyineleme ...

tek bir döngüye bile uymayanlarınız için işte brüt, tamamen gereksiz tamamen özyinelemeli bir çözüm

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

Başka bir çözüm:

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

Python Çözümüm:

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

Çıktı: ['abc', 'acb', 'bac', 'bca', 'kabin', 'cba']


0

kullanma 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]]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.