如何将数字限制在某个范围内?
我有以下代码:
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]
基本上,我是计算一个新的索引,然后用这个索引去找列表中的某个元素。为了确保这个索引在列表的范围内,我写了两个 if
语句,分成了四行。这看起来有点啰嗦,也不太美观……我敢说,这样写有点 不符合 Python 风格。
有没有更简单、更紧凑的解决方案?(而且更 符合 Python 风格)
是的,我知道可以用 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))
具体处理 Numpy 数组中值的方法,可以参考 Pythonic way to replace list values with upper and lower bound (clamping, clipping, thresholding)?。
9 个回答
69
这里有很多有趣的回答,内容大同小异,除了……哪个更快呢?
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 提到,使用普通的 Python 就可以了。numpy 版本的速度可能是所有中最慢的。这可能是因为它在寻找数组,而其他版本只是简单地对参数进行排序。
130
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
187
其实这很简单,很多人都能很快学会。你可以用注释来帮助他们理解。
new_index = max(0, min(new_index, len(mylist)-1))