Najbardziej rozwlekłe rozwiązanie nie zawsze jest najbardziej nieeleganckie. Dlatego dodaję tylko niewielką modyfikację (w celu zaoszczędzenia kilku zbędnych ocen logicznych):
def only1(l):
true_found = False
for v in l:
if v:
if true_found:
return False
else:
true_found = True
return true_found
Oto kilka czasów do porównania:
from itertools import ifilter, islice
def OP(l):
true_found = False
for v in l:
if v and not true_found:
true_found=True
elif v and true_found:
return False
return true_found
def DavidRobinson(l):
return l.count(True) == 1
def FJ(l):
return len(list(islice(ifilter(None, l), 2))) == 1
def JonClements(iterable):
i = iter(iterable)
return any(i) and not any(i)
def moooeeeep(l):
true_found = False
for v in l:
if v:
if true_found:
return False
else:
true_found = True
return true_found
Mój wynik:
$ python -mtimeit -s 'import test; l=[True]*100000' 'test.OP(l)'
1000000 loops, best of 3: 0.523 usec per loop
$ python -mtimeit -s 'import test; l=[True]*100000' 'test.DavidRobinson(l)'
1000 loops, best of 3: 516 usec per loop
$ python -mtimeit -s 'import test; l=[True]*100000' 'test.FJ(l)'
100000 loops, best of 3: 2.31 usec per loop
$ python -mtimeit -s 'import test; l=[True]*100000' 'test.JonClements(l)'
1000000 loops, best of 3: 0.446 usec per loop
$ python -mtimeit -s 'import test; l=[True]*100000' 'test.moooeeeep(l)'
1000000 loops, best of 3: 0.449 usec per loop
Jak widać, rozwiązanie OP jest znacznie lepsze niż większość innych zamieszczonych tutaj rozwiązań. Zgodnie z oczekiwaniami najlepsze są te z zachowaniem zwarciowym, zwłaszcza to rozwiązanie opublikowane przez Jona Clementsa. Przynajmniej w przypadku dwóch wczesnych True
wartości na długiej liście.
Tutaj to samo dla żadnej True
wartości:
$ python -mtimeit -s 'import test; l=[False]*100000' 'test.OP(l)'
100 loops, best of 3: 4.26 msec per loop
$ python -mtimeit -s 'import test; l=[False]*100000' 'test.DavidRobinson(l)'
100 loops, best of 3: 2.09 msec per loop
$ python -mtimeit -s 'import test; l=[False]*100000' 'test.FJ(l)'
1000 loops, best of 3: 725 usec per loop
$ python -mtimeit -s 'import test; l=[False]*100000' 'test.JonClements(l)'
1000 loops, best of 3: 617 usec per loop
$ python -mtimeit -s 'import test; l=[False]*100000' 'test.moooeeeep(l)'
100 loops, best of 3: 1.85 msec per loop
Nie sprawdzałem istotności statystycznej, ale co ciekawe, tym razem podejścia sugerowane przez FJ, a zwłaszcza to Jona Clementsa, ponownie wydają się wyraźnie lepsze.