2009-07-29 4 views
11

Ich refactoring eine Funktion, die, angesichts einer Reihe von Endpunkten, die implizit Intervalle definieren, überprüft, ob eine Zahl im Intervall enthalten ist, und dann eine entsprechende zurückgeben (nicht in irgendeiner berechenbaren Weise verwandt)). Der Code, der nun die Arbeit ist der Umgang ist:Python: Zuordnung von Intervallen zu Werten

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 

Welche IMO ganz schrecklich, und es fehlt ihm, dass beide die Intervalle und die Rückgabewerte sind hartcodiert. Jede Verwendung von Datenstrukturen ist natürlich möglich.

Antwort

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

+1 Ich mag das. Du lernst jeden Tag etwas Neues. – kjfletch

+0

+1: unglaublich! –

+1

Wirklich beeindruckend. Super sauber, und ich glaube auch sehr schnell. Es kann auch leicht erweitert werden, falls man eine nicht natürliche Ordnung oder etwas anderes im Gegenzug benötigt, wie eine Zeichenkette: Import Halbierung n = Halbierung.bisect_left ([100,300,500,800,1000], p) a = ["abwesend", "niedrig", "durchschnittlich", "hoch", "sehr hoch", "extrem"] a [n] – Agos

0

versuchen, etwas entlang der Linien von:

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

Sie könnten ein Nehmen auf diese versuchen:

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) 

produziert:

0 
1 
2 

Wie immer in Python, es wird irgendwelche besseren Möglichkeiten, es zu tun.

+0

Berücksichtigt nicht den Fall von p> 1000! – stefanw

+0

Deshalb habe ich angegeben: "Sie könnten versuchen, dies zu tun" – kjfletch

+0

Dieser letzte Satz ist ironisch, in Anbetracht der Python-Philosophie, vorzugsweise nur einen offensichtlichen Weg zu haben, etwas zu tun. – sykora

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

Gehen Sie Ihre Endpunkte als Liste in endpoints, wie folgt aus:

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

Edit:

Die oben eine lineare Suche ist. Glenn Maynards Antwort wird eine bessere Leistung haben, da sie einen Bisektionsalgorithmus verwendet.

+0

Verliere das "vorherige" Kapern; es ist ziemlich überflüssig. –

+0

Ja, du hast recht, ich denke, der ursprüngliche Code hat mich dazu inspiriert, ihn zu benutzen. Übrigens könnte Ihre Verwendung des Imperativs für einige etwas schroff klingen. – Steef

+0

@Steef: Vielleicht möchten Sie einen bescheidenen Vorschlag, dass Sie in Ihrer Freizeit Ihre Antwort revidieren könnten, zu beachten, dass ** Ihre Antwort immer noch eine redundante Codezeile enthält **, und in der Fülle der Zeit, die gleiche Verbrauchssteuer. –

0

Eine andere Art und Weise ...

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

Es ist in der Tat ziemlich schrecklich. Ohne eine Anforderung keine Hardcoding zu haben, sollte es so geschrieben wurde:

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 

Hier Beispiele sind eine Lookup-Funktion zu schaffen, sowohl linearen als auch unter Verwendung von binärer Suche, mit der No-hardcodings Anforderung erfüllt, und ein paar der Plausibilitätsprüfungen für die beiden Tabellen:

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

Ich mag dieses besser als der, der aufgrund seiner allgemeineren/nicht-hartcodierten Form die meisten Stimmen hat und weil er detaillierter ist. – JAB