Baru-baru ini saya menulis sebuah fungsi untuk menghasilkan urutan tertentu dengan batasan nontrivial. Masalahnya datang dengan solusi rekursif alami. Sekarang kebetulan, bahkan untuk input yang relatif kecil, urutannya beberapa ribu, jadi saya lebih suka menggunakan algoritme saya sebagai generator daripada menggunakannya untuk mengisi daftar dengan semua urutan.
Berikut ini contohnya. Misalkan kita ingin menghitung semua permutasi string dengan fungsi rekursif. Algoritme naif berikut mengambil 'penyimpanan' argumen ekstra dan menambahkan permutasi padanya setiap kali menemukannya:
def getPermutations(string, storage, prefix=""):
if len(string) == 1:
storage.append(prefix + string) # <-----
else:
for i in range(len(string)):
getPermutations(string[:i]+string[i+1:], storage, prefix+string[i])
storage = []
getPermutations("abcd", storage)
for permutation in storage: print permutation
(Tolong jangan pedulikan inefisiensi, ini hanya sebuah contoh.)
Sekarang saya ingin mengubah fungsi saya menjadi generator, yaitu untuk menghasilkan permutasi daripada menambahkannya ke daftar penyimpanan:
def getPermutations(string, prefix=""):
if len(string) == 1:
yield prefix + string # <-----
else:
for i in range(len(string)):
getPermutations(string[:i]+string[i+1:], prefix+string[i])
for permutation in getPermutations("abcd"):
print permutation
Kode ini tidak berfungsi (fungsi berperilaku seperti generator kosong).
Apakah saya melewatkan sesuatu? Apakah ada cara untuk mengubah algoritma rekursif di atas menjadi generator tanpa menggantinya dengan yang berulang ?
yield from getPermutations(string[:i] + string[i+1:])
, yang lebih efisien dalam banyak hal!