web-dev-qa-db-ja.com

整数をある範囲に固定する方法は?

私は次のコードを持っています:

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

基本的に、新しいインデックスを計算し、それを使用してリストから要素を見つけます。インデックスがリストの境界内にあることを確認するために、4行に広がる2つのifステートメントを記述する必要がありました。それはかなり冗長で、少しい...あえて言う、それはかなりun-Pythonicです。

他のよりシンプルでコンパクトなソリューションはありますか?(およびその他Pythonic

はい、私は_if else_を1行で使用できることを知っていますが、それは読めません:

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

実際、これは非常に明確です。多くの人がすぐにそれを学びます。コメントを使用して支援することができます。

new_index = max(0, min(new_index, len(mylist)-1))
102
S.Lott
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
74
John La Rooy

numpy.clip を参照してください:

index = numpy.clip(index, 0, len(my_list) - 1)
36
Neil G

ここでは多くの興味深い答えがありますが、ほぼ同じですが、どちらが速いですか?

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 has !!、普通のpythonを使用します。 numpyバージョンは、おそらく驚くことではないが、最も遅いものです。おそらく、他のバージョンが引数を並べるだけの配列を探しているからでしょう。

大好きな読みやすい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)

必要に応じて、最小/最大をリストにして、より「数学的に純粋」に見えるようにすることもできます。

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

max()min()を連結することは、私が見た通常のイディオムです。読みにくい場合は、操作をカプセル化するヘルパー関数を作成します。

def clamp(minimum, x, maximum):
    return max(minimum, min(x, maximum))
13

コードが扱いにくいと思われる場合は、関数が役立つ場合があります。

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

new_index = clamp(0, new_index, len(mylist)-1)
5
Greg Hewgill

これは私にはもっとPythonicらしい:

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

コードを混乱させるため、頻繁に適用しない限り、このような小さなタスクの関数を作成しないでください。

個々の値の場合:

min(clamp_max, max(clamp_min, value))

値のリストの場合:

map(lambda x: min(clamp_max, max(clamp_min, x)), values)
1
Jetze Schaafsma