2010-11-03 428 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