2009-07-29 7 views
11

Je suis en train de refactoriser une fonction qui, étant donné une série de points de terminaison qui définissent implicitement des intervalles, vérifie si un nombre est inclus dans l'intervalle, puis renvoie un correspondant (non lié de manière calculable). Le code qui gère maintenant le travail est:Python: mappage d'intervalles à des valeurs

if p <= 100: 
    return 0 
elif p > 100 and p <= 300: 
    return 1 
elif p > 300 and p <= 500: 
    return 2 
elif p > 500 and p <= 800: 
    return 3 
elif p > 800 and p <= 1000: 
    return 4 
elif p > 1000: 
    return 5 

Ce qui est tout à fait l'OMI horrible, et manque en ce que les intervalles et les valeurs de retour sont hardcoded. Toute utilisation de toute structure de données est bien sûr possible.

Répondre

35
import bisect 
bisect.bisect_left([100,300,500,800,1000], p) 
+0

+1 J'aime ça. Vous apprenez quelque chose de nouveau chaque jour. – kjfletch

+0

+1: incroyable! –

+1

Vraiment impressionnant. Super propre, et je crois très vite aussi. Il peut également être facilement étendu dans le cas où on a besoin d'un ordre non-naturel ou autre chose en retour, comme une chaîne: import bisect n = bisect.bisect_left ([100,300,500,800,1000], p) a = ["absent", "bas", "moyen", "haut", "très élevé", "extrême"] a [n] – Agos

0

Essayez quelque chose le long des lignes de:

d = {(None,100): 0, 
    (100,200): 1, 
    ... 
    (1000, None): 5} 
value = 300 # example value 
for k,v in d.items(): 
    if (k[0] is None or value > k[0]) and (k[1] is None or value <= k[1]): 
     return v 
3

Vous pouvez essayer une prise à ce sujet:

def check_mapping(p): 
    mapping = [(100, 0), (300, 1), (500, 2)] # Add all your values and returns here 

    for check, value in mapping: 
     if p <= check: 
      return value 

print check_mapping(12) 
print check_mapping(101) 
print check_mapping(303) 

produit:

0 
1 
2 

Comme toujours en Python, il y aura de meilleures façons de le faire.

+0

Ne considère pas le cas de p> 1000! – stefanw

+0

C'est pourquoi j'ai spécifié: "Vous pourriez essayer de prendre ceci" – kjfletch

+0

Cette dernière phrase est ironique, considérant la philosophie python d'avoir de préférence seulement une façon évidente de faire quelque chose. – sykora

0
def which_interval(endpoints, number): 
    for n, endpoint in enumerate(endpoints): 
     if number <= endpoint: 
      return n 
     previous = endpoint 
    return n + 1 

passer votre extrémités comme une liste endpoints, comme ceci:

which_interval([100, 300, 500, 800, 1000], 5) 

Edit:

Ce qui précède est une recherche linéaire. La réponse de Glenn Maynard aura de meilleures performances, car elle utilise un algorithme de bissection.

+0

Perdre la câpre "précédente"; c'est assez redondant. –

+0

Ouais, vous avez raison, je suppose que le code original "m'a inspiré" pour l'utiliser. BTW, votre utilisation de l'impératif peut sembler un peu bourru à certains. – Steef

+0

@Steef: Vous pouvez envisager une humble suggestion que vous pourriez à votre guise revist votre réponse, notez que ** votre réponse comprend encore une ligne redondante de code **, et dans le temps, l'accise la même chose. –

0

Une autre façon ...

def which(lst, p): 
    return len([1 for el in lst if p > el]) 

lst = [100, 300, 500, 800, 1000] 
which(lst, 2) 
which(lst, 101) 
which(lst, 1001) 
3

Il est en effet tout à fait horrible. Sans obligation d'avoir pas hardcoding, il aurait dû être écrit comme ceci:

if p <= 100: 
    return 0 
elif p <= 300: 
    return 1 
elif p <= 500: 
    return 2 
elif p <= 800: 
    return 3 
elif p <= 1000: 
    return 4 
else: 
    return 5 

Voici des exemples de création d'une fonction de recherche, à la fois linéaire et en utilisant la recherche binaire, avec l'exigence non-hardcodings remplie, et un couple des contrôles de santé mentale sur les deux tables:

def make_linear_lookup(keys, values): 
    assert sorted(keys) == keys 
    assert len(values) == len(keys) + 1 
    def f(query): 
     return values[sum(1 for key in keys if query > key)] 
    return f 

import bisect 
def make_bisect_lookup(keys, values): 
    assert sorted(keys) == keys 
    assert len(values) == len(keys) + 1 
    def f(query): 
     return values[bisect.bisect_left(keys, query)] 
    return f 
+0

J'aime mieux celui-ci que celle qui a le plus de votes en raison de sa forme plus généralisée/non codée en dur et parce qu'elle est plus en profondeur. – JAB

Questions connexes