Rozwiązałem zagadkę programistyczną obejmującą kombinacje. Doprowadziło mnie to do wspaniałej funkcji itertools.combinations
i chciałbym wiedzieć, jak to działa pod maską. Dokumentacja mówi, że algorytm jest z grubsza równoważna następującej:Algorytm dla itertools.combinations w Pythonie
def combinations(iterable, r):
# combinations('ABCD', 2) --> AB AC AD BC BD CD
# combinations(range(4), 3) --> 012 013 023 123
pool = tuple(iterable)
n = len(pool)
if r > n:
return
indices = list(range(r))
yield tuple(pool[i] for i in indices)
while True:
for i in reversed(range(r)):
if indices[i] != i + n - r:
break
else:
return
indices[i] += 1
for j in range(i+1, r):
indices[j] = indices[j-1] + 1
yield tuple(pool[i] for i in indices)
Mam pomysł: zaczynamy od najbardziej oczywistych kombinacji (r
pierwsze kolejnymi elementami). Następnie zmieniamy jeden (ostatni) element, aby uzyskać każdą kolejną kombinację.
To, z czym walczę, to uwarunkowana pętla for
.
for i in reversed(range(r)):
if indices[i] != i + n - r:
break
Ta ekspedycja jest bardzo zwięzła i podejrzewam, że dzieje się tam, gdzie dzieje się cała magia. Proszę, daj mi podpowiedź, abym mógł to zrozumieć.
Należy zauważyć, że to tylko część pętli. Wygląda na to, że zepsułoby to większość czasu, ale zamiast tego przerwa zapobiegnie powrotowi w ['else'] (https://docs.python.org/2/tutorial/controlflow.html# Wyrażenia "kontynuuj i kontynuuj" oraz "else-else-klauzule-pętle"). –