How to clamp an integer to some range?

2019-01-05 01:51发布

I have the following code:

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]

Basically, I calculate a new index and use that to find some element from a list. In order to make sure the index is inside the bounds of the list, I needed to write those 2 if statements spread into 4 lines. That's quite verbose, a bit ugly... Dare I say, it's quite un-pythonic.

Is there any other simpler and more compact solution? (and more pythonic)

Yes, i know I can use if else in one line, but it is not readable:

new_index = 0 if new_index < 0 else len(mylist) - 1 if new_index >= len(mylist) else new_index

I also know I can chain max() and min() together. It's more compact, but I feel it's kinda obscure, more difficult to find bugs if I type it wrong. In other words, I don't find it very straightforward.

new_index = max(0, min(new_index, len(mylist)-1))

标签: python clamp
9条回答
孤傲高冷的网名
2楼-- · 2019-01-05 01:57

See numpy.clip:

index = numpy.clip(index, 0, len(my_list) - 1)
查看更多
做个烂人
3楼-- · 2019-01-05 02:00

Avoid writing functions for such small tasks, unless you apply them often, as it will clutter up your code.

for individual values:

min(clamp_max, max(clamp_min, value))

for lists of values:

map(lambda x: min(clamp_max, max(clamp_min, x)), values)
查看更多
放我归山
4楼-- · 2019-01-05 02:02

Chaining max() and min() together is the normal idiom I've seen. If you find it hard to read, write a helper function to encapsulate the operation:

def clamp(minimum, x, maximum):
    return max(minimum, min(x, maximum))
查看更多
甜甜的少女心
5楼-- · 2019-01-05 02:06

This is pretty clear, actually. Many folks learn it quickly. You can use a comment to help them.

new_index = max(0, min(new_index, len(mylist)-1))
查看更多
对你真心纯属浪费
6楼-- · 2019-01-05 02:13

If your code seems too unwieldy, a function might help:

def clamp(minvalue, value, maxvalue):
    return max(minvalue, min(value, maxvalue))

new_index = clamp(0, new_index, len(mylist)-1)
查看更多
祖国的老花朵
7楼-- · 2019-01-05 02:15

This one seems more pythonic to me:

>>> def clip(val, min_, max_):
...     return min_ if val < min_ else max_ if val > max_ else val

A few tests:

>>> clip(5, 2, 7)
5
>>> clip(1, 2, 7)
2
>>> clip(8, 2, 7)
7
查看更多
登录 后发表回答