Bagaimana Anda menghasilkan semua permutasi daftar dalam Python, terlepas dari jenis elemen dalam daftar itu?
Sebagai contoh:
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]
python
algorithm
permutation
combinatorics
python-2.5
Ricardo Reyes
sumber
sumber
Jawaban:
Dimulai dengan Python 2.6 (dan jika Anda berada di Python 3) Anda memiliki standar-library alat untuk ini:
itertools.permutations
.Jika Anda menggunakan Python yang lebih lama (<2.6) karena alasan tertentu atau hanya ingin tahu cara kerjanya, berikut ini satu pendekatan yang bagus, diambil dari http://code.activestate.com/recipes/252178/ :
Beberapa pendekatan alternatif tercantum dalam dokumentasi
itertools.permutations
. Ini dia:Dan yang lain, berdasarkan
itertools.product
:sumber
for i in range(len(elements))
bukanfor i in range(len(elements)+1)
. Faktanya, elemen yang dipilihelements[0:1]
dapat berada dilen(elements)
posisi yang berbeda, sehingga hasilnya tidaklen(elements)+1
.Dan dengan Python 2.6 dan seterusnya:
(dikembalikan sebagai generator. Gunakan
list(permutations(l))
untuk kembali sebagai daftar.)sumber
r
parameter, misalnyaitertools.permutations([1,2,3], r=2)
, yang akan menghasilkan semua kemungkinan permutasi dengan memilih 2 elemen:[(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
Kode berikut dengan Python 2.6 dan di atas SAJA
Pertama, impor
itertools
:Permutasi (masalah pesanan):
Kombinasi (pesanan TIDAK masalah):
Produk Cartesian (dengan beberapa iterables):
Produk Cartesian (dengan satu iterable dan sendiri):
sumber
disebut sebagai:
sumber
Keluaran:
Saat saya menukar konten daftar itu diperlukan jenis urutan yang bisa berubah sebagai input. Misalnya
perm(list("ball"))
akan bekerja danperm("ball")
tidak akan karena Anda tidak dapat mengubah string.Implementasi Python ini terinspirasi oleh algoritma yang disajikan dalam buku Algoritma Komputer oleh Horowitz, Sahni dan Rajasekeran .
sumber
Solusi ini mengimplementasikan generator, untuk menghindari memegang semua permutasi pada memori:
sumber
Dalam gaya fungsional
Hasil:
sumber
Kode berikut adalah permutasi di tempat dari daftar yang diberikan, diimplementasikan sebagai generator. Karena hanya mengembalikan referensi ke daftar, daftar tidak boleh dimodifikasi di luar generator. Solusinya adalah non-rekursif, jadi gunakan memori rendah. Bekerja dengan baik juga dengan banyak salinan elemen dalam daftar input.
sumber
Cara yang cukup jelas menurut saya mungkin juga:
sumber
Keluaran:
sumber
Saya menggunakan algoritma yang didasarkan pada sistem bilangan faktorial - Untuk daftar panjang n, Anda dapat mengumpulkan setiap item permutasi dengan item, memilih dari item yang tersisa di setiap tahap. Anda memiliki n pilihan untuk item pertama, n-1 untuk item kedua, dan hanya satu untuk item terakhir, sehingga Anda dapat menggunakan digit angka dalam sistem angka faktorial sebagai indeks. Dengan cara ini angka 0 hingga n! -1 berhubungan dengan semua permutasi yang mungkin dalam urutan leksikografis.
keluaran:
Metode ini non-rekursif, tetapi sedikit lebih lambat di komputer saya dan xrange memunculkan kesalahan ketika n! terlalu besar untuk dikonversi ke integer C panjang (n = 13 untuk saya). Sudah cukup ketika saya membutuhkannya, tapi itu bukan itertools.permutasi oleh tembakan panjang.
sumber
Perhatikan bahwa algoritma ini memiliki
n factorial
kompleksitas waktu, di manan
panjang daftar inputCetak hasilnya dalam pelarian:
Contoh:
Keluaran:
sumber
Seseorang memang bisa mengulangi elemen pertama dari setiap permutasi, seperti pada jawaban twwenn. Namun lebih efisien untuk menulis solusi ini dengan cara ini:
Solusi ini sekitar 30% lebih cepat, tampaknya berkat rekursi yang berakhir pada
len(elements) <= 1
bukan0
. Ini juga jauh lebih hemat memori, karena menggunakan fungsi generator (melaluiyield
), seperti dalam solusi Riccardo Reyes.sumber
Ini terinspirasi oleh implementasi Haskell menggunakan pemahaman daftar:
sumber
Implementasi reguler (tanpa hasil - akan melakukan segalanya dalam memori):
Implementasi hasil:
Ide dasarnya adalah untuk membahas semua elemen dalam array untuk posisi 1, dan kemudian di posisi 2 memeriksa semua elemen tanpa elemen yang dipilih untuk 1, dll. Anda dapat melakukan ini dengan rekursi , di mana kriteria stop mencapai array 1 elemen - dalam hal ini Anda mengembalikan array itu.
sumber
perms = getPermutations(array[:i] + array[i+1:])
numpy
array _>getPermutations(np.array([1, 2, 3]))
, saya melihatnya berfungsi untuk daftar, baru saja bingung karena func arg adalaharray
:)numba
dan menjadi serakah dengan kecepatan jadi coba gunakan secara eksklusif dengannumpy
arrayUntuk kinerja, solusi numpy yang terinspirasi oleh Knuth , (hal 22):
Menyalin blok memori yang besar menghemat waktu - 20x lebih cepat dari
list(itertools.permutations(range(n))
:sumber
sumber
Berikut adalah algoritme yang berfungsi pada daftar tanpa membuat daftar perantara baru yang mirip dengan solusi Ber di https://stackoverflow.com/a/108651/184528 .
Anda dapat mencoba kode ini sendiri di sini: http://repl.it/J9v
sumber
Keindahan rekursi:
sumber
Algoritme ini adalah yang paling efektif, menghindari array passing dan manipulasi dalam panggilan rekursif, bekerja dengan Python 2, 3:
Pemakaian:
sumber
sumber
PENDEKATAN LAIN (tanpa lib)
Input dapat berupa string atau daftar
sumber
[1, 2, 3]
kembali[6, 6, 6, 6, 6, 6]
print(permutation(['1','2','3']))
Penafian: plug tak berbentuk oleh penulis paket. :)
The pengeliling paket berbeda dari kebanyakan implementasi dalam hal menghasilkan daftar semu yang tidak benar-benar berisi permutasi melainkan menggambarkan pemetaan antara permutasi dan posisi masing dalam pemesanan, sehingga memungkinkan untuk bekerja dengan sangat besar 'daftar' permutasi, seperti yang ditunjukkan dalam demo ini yang melakukan operasi yang sangat instan dan mencari dalam daftar semu 'berisi' semua permutasi dari huruf-huruf dalam alfabet, tanpa menggunakan lebih banyak memori atau pemrosesan daripada halaman web biasa.
Bagaimanapun, untuk menghasilkan daftar permutasi, kita dapat melakukan hal berikut.
Keluaran:
sumber
Hasilkan semua permutasi yang mungkin
Saya menggunakan python3.4:
Kasus uji:
sumber
Untuk menyelamatkan Anda dari kemungkinan berjam-jam mencari dan bereksperimen, berikut ini adalah solusi permutasi non-rekursif dalam Python yang juga bekerja dengan Numba (pada v. 0.41):
Untuk memberi kesan tentang kinerja:
Jadi gunakan versi ini hanya jika Anda harus memanggilnya dari fungsi njitted, jika tidak, pilih itertools implementasinya.
sumber
Saya melihat banyak iterasi terjadi di dalam fungsi rekursif ini, bukan rekursi murni ...
jadi bagi Anda yang tidak dapat mematuhi bahkan satu loop, inilah solusi rekursif sepenuhnya, benar-benar tidak perlu
sumber
Solusi lain:
sumber
Solusi Python Saya:
sumber
Output: ['abc', 'acb', 'bac', 'bca', 'cab', 'cba']
sumber
Menggunakan
Counter
sumber