2010-09-08 6 views
10

J'ai une fonction qui est passé deux valeurs, puis itère sur la gamme de ces valeurs. Les valeurs peuvent être passées dans n'importe quel ordre, donc j'ai besoin de trouver lequel est le plus bas en premier. J'ai eu la fonction écrite comme ceci:Meilleur moyen de trouver max et min de deux valeurs

def myFunc(x, y): 
    if x > y: 
     min_val, max_val = y, x 
    else: 
     min_val, max_val = x, y 
    for i in range(min_val, max_val): 
    ... 

Mais pour sauver un peu d'espace à l'écran, je fini par changer à:

def myFunc(x, y): 
    min_val, max_val = sorted([x, y]) 
    for i in range(min_val, max_val): 
    ... 

Comment est-ce mauvais? Y a-t-il un meilleur moyen qui soit encore une ligne?

Répondre

4

À moins que vous devez microoptimise, je voudrais juste à ce

def myFunc(x, y): 
    for i in range(*sorted((x, y))): 
     ... 

C'est plus rapide quoique

def myFunc(x, y): 
    for i in range(x,y) if x<y else range(y,x): 
     ... 

minmax.py

def f1(x, y): 
    for i in range(min(x, y), max(x, y)): 
     pass 

def f2(x, y): 
    for i in range(*sorted((x, y))): 
     pass 

def f3(x, y): 
    for i in range(x, y) if x<y else range(y, x): 
     pass 

def f4(x, y): 
    if x>y: 
     x,y = y,x 
    for i in range(x, y): 
     pass 

def f5(x, y): 
    mn,mx = ((x, y), (y, x))[x>y] 
    for i in range(x,y): 
     pass 

benchmarks ( f3 est le plus rapide egardless de l'ordre)

$ python -m timeit -s"import minmax as mm" "mm.f1(1,2)" 
1000000 loops, best of 3: 1.93 usec per loop 
$ python -m timeit -s"import minmax as mm" "mm.f2(1,2)" 
100000 loops, best of 3: 2.4 usec per loop 
$ python -m timeit -s"import minmax as mm" "mm.f3(1,2)" 
1000000 loops, best of 3: 1.16 usec per loop 
$ python -m timeit -s"import minmax as mm" "mm.f4(1,2)" 
100000 loops, best of 3: 1.2 usec per loop 
$ python -m timeit -s"import minmax as mm" "mm.f5(1,2)" 
1000000 loops, best of 3: 1.58 usec per loop 
$ python -m timeit -s"import minmax as mm" "mm.f1(2,1)" 
100000 loops, best of 3: 1.88 usec per loop 
$ python -m timeit -s"import minmax as mm" "mm.f2(2,1)" 
100000 loops, best of 3: 2.39 usec per loop 
$ python -m timeit -s"import minmax as mm" "mm.f3(2,1)" 
1000000 loops, best of 3: 1.18 usec per loop 
$ python -m timeit -s"import minmax as mm" "mm.f4(2,1)" 
1000000 loops, best of 3: 1.25 usec per loop 
$ python -m timeit -s"import minmax as mm" "mm.f5(2,1)" 
1000000 loops, best of 3: 1.44 usec per loop 
15

min et max sont vos amis.

def myFunc(x, y): 
    min_val, max_val = min(x, y), max(x, y) 

Modifier. Benchmarké min-max version againt un simple if. En raison de la surcharge de l'appel de fonction, min-max prend 2.5x plus longtemps que le if simple; voir http://gist.github.com/571049

+0

Je n'y avais même pas pensé à le faire en une ligne. Mais selon la façon dont le tri est mis en œuvre, il pourrait être moins efficace. Je sais que le tri de la bibliothèque standard en C++ est codé en dur pour les éléments <7, donc le tri d'une liste de deux éléments ne serait qu'une simple comparaison. Cependant, il y a le coût supplémentaire de la création d'un objet liste. – Colin

4

J'aime le sorted un. Intelligent mais pas trop intelligent. Voici quelques autres options.

def myFunc(min, max): 
    if min > max: min, max = max, min 

def myFunc(x, y): 
    min, max = min(x, y), max(x, y) 

def myFunc(x, y): 
    min, max = [f(x, y) for f in (min, max)] 

Le dernier est un peu idiot je l'admets.

+2

Il est préférable d'utiliser d'autres noms que min et max, car ce sont des compilations Python. –

1

Quelques suggestions

def myfunc(minVal, maxVal): 
    if minVal > maxVal: minVal, maxVal = maxVal, minVal 

def myfunc2(a, b): 
    minVal, maxVal = ((a, b), (b, a))[a > b] # :-P 

Utilisation triés, les min/max builtins ou la deuxième solution semble au-dessus surpuissance dans ce cas.

Et rappelez-vous que range(min, max) passera de min à max - 1!

2

La meilleure réponse fonctionne comme:

def foo(lo, hi): 
    if hi < lo: lo,hi = hi,lo 

Il est clair, fait un point, et ne sens obscur dans un tas de colle supplémentaire. C'est court. C'est presque certainement aussi rapide que n'importe quelle autre option dans la pratique, et elle repose sur le moins d'intelligence.

4

Depuis la question de l'OP a été posée à l'aide x et y en tant que paramètres (non lo et hi), j'irais avec (pour la vitesse et la clarté):

def myfunc(x, y): 
    lo, hi = (x, y) if x < y else (y, x) 

>>> timeit.repeat("myfunc(10, 5)", "from __main__ import myfunc") 
[1.2527812156004074, 1.185214249195269, 1.1886092749118689] 
>>> timeit.repeat("foo(10, 5)", "from __main__ import foo") 
[1.0397177348022524, 0.9580022495574667, 0.9673979369035806] 
>>> timeit.repeat("f3(10, 5)", "from __main__ import f3") 
[2.47303065772212, 2.4192818561823515, 2.4132735135754046] 
+0

bon usage de déballage, j'aime cette réponse mieux – timgeb

Questions connexes