Ответ 1
На самом деле это довольно ясно. Многие люди учатся быстро. Вы можете использовать комментарий, чтобы помочь им.
new_index = max(0, min(new_index, len(mylist)-1))
У меня есть следующий код:
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]
В принципе, я вычисляю новый индекс и использую его, чтобы найти какой-то элемент из списка. Чтобы убедиться, что индекс находится внутри границ списка, мне нужно было написать эти операторы 2 if
, разбросанные по 4 строкам. Это довольно многословие, немного уродливое... Смею сказать, это совершенно непитоноязычное.
Есть ли еще более простое и компактное решение? (и более pythonic)
Да, я знаю, что я могу использовать if else
в одной строке, но не читаем:
new_index = 0 if new_index < 0 else len(mylist) - 1 if new_index >= len(mylist) else new_index
Я также знаю, что могу объединить max()
и min()
вместе. Это более компактно, но я чувствую, что это неясно, сложнее найти ошибки, если я напечатаю его неправильно. Другими словами, я не считаю это очень простым.
new_index = max(0, min(new_index, len(mylist)-1))
На самом деле это довольно ясно. Многие люди учатся быстро. Вы можете использовать комментарий, чтобы помочь им.
new_index = max(0, min(new_index, len(mylist)-1))
sorted((minval, value, maxval))[1]
например:
>>> 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
См. numpy.clip:
index = numpy.clip(index, 0, len(my_list) - 1)
много интересных ответов здесь, все о том же, кроме... что быстрее?
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 имеет это!, используйте plain ol 'python. Версия numpy, возможно, не удивительно, самая медленная партия. Возможно, потому, что он ищет массивы, где другие версии просто упорядочивают свои аргументы.
Что случилось с моим любимым читаемым языком Python?: -)
Серьезно, просто сделайте это функцией:
def addInRange (val, add, minval, maxval):
newval = val + add
if newval < minval: return minval
if newval > maxval: return maxval
return newval
то просто назовите его чем-то вроде:
val = addInRange (val, 7, 0, 42)
Или более простое, более гибкое решение, в котором вы сами вычисляете:
def restrict (val, minval, maxval):
if val < minval: return minval
if val > maxval: return maxval
return val
x = restrict (x+10, 0, 42)
Если бы вы этого захотели, вы даже могли бы составить список min/max, чтобы он выглядел более "математически чистым":
x = restrict (val+7, [0, 42])
Цепочка max()
и min()
вместе - это нормальная идиома, которую я видел. Если вам трудно читать, напишите вспомогательную функцию для инкапсуляции операции:
def clamp(minimum, x, maximum):
return max(minimum, min(x, maximum))
Если ваш код кажется слишком громоздким, функция может помочь:
def clamp(minvalue, value, maxvalue):
return max(minvalue, min(value, maxvalue))
new_index = clamp(0, new_index, len(mylist)-1)
Избегайте писать функции для таких небольших задач, если вы не применяете их часто, так как это загромождает ваш код.
для отдельных значений:
min(clamp_max, max(clamp_min, value))
для списков значений:
map(lambda x: min(clamp_max, max(clamp_min, x)), values)
Это кажется мне более pythonic:
>>> def clip(val, min_, max_):
... return min_ if val < min_ else max_ if val > max_ else val
Несколько тестов:
>>> clip(5, 2, 7)
5
>>> clip(1, 2, 7)
2
>>> clip(8, 2, 7)
7