Как зажать целое число некоторому диапазону?

StackOverflow https://stackoverflow.com/questions/4092528

  •  28-09-2019
  •  | 
  •  

Вопрос

У меня есть следующий код:

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 строки. Это довольно многословно, немного некрасиво ... не смею говорить, это совсем ООН-Питон.

Есть ли другие проще и более компактное решение? (и более питон)

Да, я знаю, что могу использовать 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. Имеет это!, используйте простой питон. Numpy версия, возможно, не удивительно, самая медленная лота. Вероятно, потому что он ищет массивы, где другие версии просто заказывают свои аргументы.

Цепочка max() и min() вместе нормальная идиома, которую я видел. Если вам трудно прочитать, напишите функцию помощника для инкапсуляции операции:

def clamp(minimum, x, maximum):
    return max(minimum, min(x, maximum))

Что бы ни случилось с моим любимым читаемым языком 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])

Этот кажется больше питонским для меня:

>>> 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

Если ваш код кажется слишком громоздким, функция может помочь:

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)
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top