如何将数字限制在某个范围内?

159 投票
9 回答
201755 浏览
提问于 2025-04-16 06:31

我有以下代码:

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

撰写回答