2010-11-03 441 views
65

我有以下代码:如何将整数限制在某个范围内? (在Python)

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

还有其他更简单更紧凑的解决方案吗?(更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)) 
+1

如果感觉“有点晦涩”,做一个函数出来的吗? – Santa 2010-11-03 23:40:33

+1

是的,我可以写一个函数,但那不是重点。问题是如何实现(内联或在函数中)。 – 2010-11-05 12:15:35

+0

'clamp = lambda value,minv,maxv:max(min(value,maxv),minv)'使用http://arma.sourceforge.net/docs.html#clamp的API – 2015-12-01 08:41:47

回答

71

这实际上很清楚。许多人很快就学会了。您可以使用评论来帮助他们。

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

尽管我觉得它不是作为pythonic应该是,我也觉得这是我们现在最好的解决方案。 – 2010-11-13 01:14:26

+21

'def clamp(n,最小,最大):返回最大(最小,最小(n,最大))' – csl 2015-09-21 11:05:55

+2

@csl人们总是提供这些小帮手功能,但我永远不知道把它们放在哪里。 'helperFunctions.py'?一个单独的模块?如果这种情况充斥着各种“辅助功能”,完全不同的事情呢? – 2017-05-25 02:01:44

5

如果你的代码似乎太笨重,功能可能会有所帮助:

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

new_index = clamp(0, new_index, len(mylist)-1) 
12

不管发生在我心爱的可读的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) 

如果你想,你甚至可以使最小/最大的列表,所以它看起来更“米athematically纯“:

x = restrict (val+7, [0, 42]) 
+5

把它放在一个函数中是好的(并建议,如果你做了很多),但我认为'min'和'max'比一堆条件清晰得多。 (我不知道'add'是什么意思 - 只是说'clamp(val + 7,0,42)'。) – 2010-11-03 23:40:02

12

链接max()min()在一起是正常的成语我见过。如果你觉得很难读,写一个辅助函数封装操作:

def clamp(minimum, x, maximum): 
    return max(minimum, min(x, maximum)) 
59
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 
+4

+1用于'sorted()'内置的创造性使用。非常紧凑,但它只是有点模糊。无论如何,看到其他创意解决方案总是很好的! – 2010-11-04 00:06:50

+7

非常有创意,实际上与min(max())结构一样快。在数量在范围内并且不需要交换的情况下,速度会稍微快一点。 – kindall 2010-11-04 00:35:07

34

numpy.clip

index = numpy.clip(index, 0, len(my_list) - 1) 
+0

[The docs](http://docs.scipy.org/doc/numpy/reference/generated/numpy.clip.html)表示'clip'的第一个参数是'a',一个包含剪辑元素的数组”。所以你必须编写'numpy.clip([index],...',而不是'numpy.clip(index,...' – 2013-08-27 21:20:54

+8

@ RoryO'Kane:你试过吗? – 2013-08-28 00:33:06

+1

熊猫还允许在Series和DataFrame上使用它,和面板 – 2017-07-06 09:58:06

2

避免写功能对于这样的小任务,除非你经常应用它们,因为它会混淆你的代码。

单一数值:

min(clamp_max, max(clamp_min, value)) 

的值列表:

map(lambda x: min(clamp_max, max(clamp_min, x)), values) 
26

很多有趣的答案在这里,所有关于一样的,只不过......哪一个的速度更快?

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版本可能并不令人感到意外,是最慢的。可能是因为它正在寻找数组,其他版本只是在排列他们的参数。

+0

Numpy的性能出乎意料的糟糕 – 2016-06-09 20:27:15

+6

@LenarHoyt考虑到Numpy的性能是围绕大数组设计的,而不是单个数字,并且它必须首先将整数转换为内部数据类型,并且它接受几个不同类型的输入,可能需要相当长的时间才能确定输入是什么类型以及将其转换为什么类型。如果您为它提供一个数组(最好不是列表或元组),您将看到更好的Numpy性能转换第一个)数以千计的值 – blubberdiblub 2017-01-26 21:34:38

+0

Python的速度慢了三个数量级783 ns = 783,000μs我以前犯过同样的错误,符号很微妙。 – 2017-12-19 21:23:32

2

这一次似乎更Python对我说:

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