質問
次のコードがあります。
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)
はい、私は使えることを知っています 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))
解決
実際、これはかなり明確です。多くの人がすぐにそれを学びます。コメントを使用して役立ちます。
new_index = max(0, min(new_index, len(mylist)-1))
他のヒント
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
見る numpy.clip:
index = numpy.clip(index, 0, len(my_list) - 1)
ここで多くの興味深い答え、すべてが同じことを除いて...どちらがより速いですか?
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バージョンは、おそらく驚くことではないが、最も遅いロットです。おそらく、他のバージョンが議論を注文するアレイを探しているからでしょう。
チェーン max()
と min()
一緒に私が見た通常のイディオムです。読みにくい場合は、操作をカプセル化するヘルパー関数を書き込みます。
def clamp(minimum, x, maximum):
return max(minimum, min(x, maximum))
私の最愛の読みやすい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])
これは私にとってよりパイソンのようです:
>>> 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
あなたのコードが扱いにくいように見える場合、関数は次のように役立つかもしれません
def clamp(minvalue, value, maxvalue):
return max(minvalue, min(value, maxvalue))
new_index = clamp(0, new_index, len(mylist)-1)
コードを乱雑にするため、頻繁に適用しない限り、そのような小さなタスクの機能を書くことは避けてください。
個々の値について:
min(clamp_max, max(clamp_min, value))
値のリストについて:
map(lambda x: min(clamp_max, max(clamp_min, x)), values)