web-dev-qa-db-fra.com

Comment fixer un entier à une certaine plage?

J'ai le code suivant:

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]

En gros, je calcule un nouvel index et l’utilise pour trouver un élément dans une liste. Afin de m'assurer que l'index se trouve à l'intérieur des limites de la liste, j'avais besoin d'écrire ces 2 if déclarations réparties sur 4 lignes. C'est assez verbeux, un peu moche ... J'ose le dire, c'est assez un-Pythonic .

Y a-t-il une autre solution plus simple et plus compacte? (et plus Pythonic )

Oui, je sais que je peux utiliser if else Sur une ligne, mais ce n'est pas lisible:

new_index = 0 if new_index < 0 else len(mylist) - 1 if new_index >= len(mylist) else new_index

Je sais aussi que je peux chaîner max() et min() ensemble. C'est plus compact, mais je pense que c'est un peu obscur, plus difficile de trouver des bugs si je tape mal. En d'autres termes, je ne le trouve pas très simple.

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

C'est assez clair, en fait. Beaucoup de gens l'apprennent rapidement. Vous pouvez utiliser un commentaire pour les aider.

new_index = max(0, min(new_index, len(mylist)-1))
102
S.Lott
sorted((minval, value, maxval))[1]

par exemple:

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

Voir numpy.clip :

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

beaucoup de réponses intéressantes ici, toutes à peu près les mêmes, sauf ... laquelle est la plus rapide?

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 l'a!, utilise un vieux python. La version numpy est, sans surprise, la plus lente du lot. Probablement parce qu'il recherche des tableaux, où les autres versions ordonnent simplement leurs arguments.

Qu'est-il arrivé à mon bien-aimé lisible Python? :-)

Sérieusement, juste en faire une fonction:

def addInRange(val, add, minval, maxval):
    newval = val + add
    if newval < minval: return minval
    if newval > maxval: return maxval
    return newval

alors appelez-le avec quelque chose comme:

val = addInRange(val, 7, 0, 42)

Ou une solution plus simple et plus flexible, dans laquelle vous effectuez le calcul vous-même:

def restrict(val, minval, maxval):
    if val < minval: return minval
    if val > maxval: return maxval
    return val

x = restrict(x+10, 0, 42)

Si vous le souhaitez, vous pouvez même faire du min/max une liste pour qu’elle ait l’air plus "mathématiquement pur":

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

Le chaînage max() et min() est l'idiome normal que j'ai vu. Si vous avez du mal à lire, écrivez une fonction d'assistance pour encapsuler l'opération:

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

Si votre code semble trop lourd, une fonction pourrait vous aider:

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

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

Celui-ci me semble plus pythonique:

>>> def clip(val, min_, max_):
...     return min_ if val < min_ else max_ if val > max_ else val

Quelques tests:

>>> clip(5, 2, 7)
5
>>> clip(1, 2, 7)
2
>>> clip(8, 2, 7)
7
4
Jens

Évitez d’écrire des fonctions pour de telles petites tâches, à moins que vous ne les appliquiez souvent, car cela encombrerait votre code.

pour les valeurs individuelles:

min(clamp_max, max(clamp_min, value))

pour les listes de valeurs:

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