Mam następujący kod:
new_index = index + offset
if new_index < 0:
new_index = 0
if new_index >= len(mylist):
new_index = len(mylist) - 1
return mylist[new_index]
Zasadniczo obliczam nowy indeks i używam go, aby znaleźć jakiś element z listy. Aby upewnić się, że indeks znajduje się w granicach listy, musiałem zapisać te 2 if
instrukcje rozłożone na 4 linie. To dość rozwlekłe, trochę brzydkie ... Ośmielę się powiedzieć, to całkiem nie-pytoniczne .
Czy jest jakieś inne prostsze i bardziej kompaktowe rozwiązanie? (i bardziej pythonowe )
Tak, wiem, że mogę użyć if else
w jednej linii, ale nie jest to czytelne:
new_index = 0 if new_index < 0 else len(mylist) - 1 if new_index >= len(mylist) else new_index
Wiem też, że potrafię łączyć max()
i min()
razem. Jest bardziej kompaktowy, ale wydaje mi się, że jest trochę niejasny, trudniej jest znaleźć błędy, jeśli wpiszę źle. Innymi słowy, nie uważam tego za bardzo proste.
new_index = max(0, min(new_index, len(mylist)-1))
clamp = lambda value, minv, maxv: max(min(value, maxv), minv)
Korzystanie z API z arma.sourceforge.net/docs.html#clampOdpowiedzi:
Właściwie jest to całkiem jasne. Wiele osób szybko się tego uczy. Możesz użyć komentarza, aby im pomóc.
new_index = max(0, min(new_index, len(mylist)-1))
źródło
def clamp(n, smallest, largest): return max(smallest, min(n, largest))
helperFunctions.py
? Osobny moduł? A co jeśli zostanie zaśmiecony różnymi „funkcjami pomocniczymi” do zupełnie innych rzeczy?utils.py
sorted((minval, value, maxval))[1]
na przykład:
>>> minval=3 >>> maxval=7 >>> for value in range(10): ... print sorted((minval, value, maxval))[1] ... 3 3 3 3 4 5 6 7 7 7
źródło
sorted()
wbudowanego. Bardzo kompaktowy, ale trochę niejasny. Zresztą zawsze miło jest zobaczyć inne kreatywne rozwiązania!min(max())
konstrukcja. Bardzo nieznacznie szybciej w przypadku, gdy liczba mieści się w zakresie i nie są potrzebne żadne zamiany.wiele interesujących odpowiedzi tutaj, wszystkie mniej więcej takie same, z wyjątkiem ... która jest szybsza?
import numpy np_clip = numpy.clip mm_clip = lambda x, l, u: max(l, min(u, x)) s_clip = lambda x, l, u: sorted((x, l, u))[1] py_clip = lambda x, l, u: l if x < l else u if x > u else x
>>> import random >>> rrange = random.randrange >>> %timeit mm_clip(rrange(100), 10, 90) 1000000 loops, best of 3: 1.02 µs per loop >>> %timeit s_clip(rrange(100), 10, 90) 1000000 loops, best of 3: 1.21 µs per loop >>> %timeit np_clip(rrange(100), 10, 90) 100000 loops, best of 3: 6.12 µs per loop >>> %timeit py_clip(rrange(100), 10, 90) 1000000 loops, best of 3: 783 ns per loop
paxdiablo ma to !, użyj zwykłego starego pythona. Wersja numpy jest, być może, nie jest zaskoczeniem, najwolniejsza z wielu. Prawdopodobnie dlatego, że szuka tablic, w których inne wersje po prostu porządkują swoje argumenty.
źródło
mm_clip
ipy_clip
będzie równie szybki, jeśli używasz kompilatora JIT, jak pypy. Z wyjątkiem tego, że pierwszy jest bardziej czytelny, a czytelność jest ważniejsza w filozofii Pythona niż niewielki wzrost wydajności przez większość czasu.Zobacz numpy.clip :
index = numpy.clip(index, 0, len(my_list) - 1)
źródło
clip
jesta
„tablica zawierająca elementy do przycięcia”. Więc musiałbyś pisaćnumpy.clip([index], …
, nienumpy.clip(index, …
.Łączenie
max()
imin()
razem to normalny idiom, jaki widziałem. Jeśli masz trudności z odczytaniem, napisz funkcję pomocniczą, aby hermetyzować operację:def clamp(minimum, x, maximum): return max(minimum, min(x, maximum))
źródło
Cokolwiek stało się z moim ukochanym, czytelnym językiem Pythona? :-)
Poważnie, po prostu zrób z tego funkcję:
def addInRange(val, add, minval, maxval): newval = val + add if newval < minval: return minval if newval > maxval: return maxval return newval
następnie po prostu nazwij to czymś takim:
val = addInRange(val, 7, 0, 42)
Lub prostsze, bardziej elastyczne rozwiązanie, w którym samodzielnie wykonujesz obliczenia:
def restrict(val, minval, maxval): if val < minval: return minval if val > maxval: return maxval return val x = restrict(x+10, 0, 42)
Jeśli chcesz, możesz nawet utworzyć listę min / max, aby wyglądała bardziej „matematycznie czysto”:
x = restrict(val+7, [0, 42])
źródło
min
imax
jest o wiele jaśniejsze niż kilka warunków. (Nie wiem, do czegoadd
służy - po prostu powiedzclamp(val + 7, 0, 42)
.)Ten wydaje mi się bardziej pytoniczny:
>>> def clip(val, min_, max_): ... return min_ if val < min_ else max_ if val > max_ else val
Kilka testów:
>>> clip(5, 2, 7) 5 >>> clip(1, 2, 7) 2 >>> clip(8, 2, 7) 7
źródło
Jeśli twój kod wydaje się zbyt nieporęczny, funkcja może pomóc:
def clamp(minvalue, value, maxvalue): return max(minvalue, min(value, maxvalue)) new_index = clamp(0, new_index, len(mylist)-1)
źródło
Unikaj pisania funkcji dla tak małych zadań, chyba że używasz ich często, ponieważ zaśmieca to twój kod.
dla poszczególnych wartości:
dla list wartości:
map(lambda x: min(clamp_max, max(clamp_min, x)), values)
źródło