2009-07-29 10 views
11

Reorganizuję funkcję, która, biorąc pod uwagę serię punktów końcowych, które domyślnie definiują interwały, sprawdza, czy liczba jest zawarta w przedziale, a następnie zwraca odpowiednią (niezwiązaną w żaden obliczalny sposób). Kod, który jest teraz obsługę prac jest:Python: Mapowanie z przedziałów na wartości

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 

Który jest IMO dość straszne, i nie ma tym, że zarówno odstępach i zwracane wartości są ustalony. Jakiekolwiek wykorzystanie dowolnej struktury danych jest oczywiście możliwe.

Odpowiedz

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

+1 Podoba mi się to. Każdego dnia uczysz się czegoś nowego. – kjfletch

+0

+1: niewiarygodne! –

+1

Naprawdę imponujące. Super czysty, i wierzę też bardzo szybko. Można go również łatwo rozszerzyć w przypadku, gdy potrzebna jest nienaturalna kolejność lub coś innego w zamian, np. Ciąg znaków: import bisect n = bisect.bisect_left ([100,300,500,800,1000], p) a = ["nieobecny", "niski", "średni", "wysoki", "bardzo wysoki", "skrajny"] a [n] – Agos

0

spróbować czegoś wzdłuż linii:

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

Można spróbować podjąć to:

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) 

produkuje:

0 
1 
2 

Jak zawsze w Pythonie, nie będzie lepsze sposoby na zrobienie tego.

+0

Nie uwzględnia przypadku p> 1000! – stefanw

+0

Dlatego właśnie napisałem: "Możesz spróbować wziąć to na siebie" – kjfletch

+0

To ostatnie zdanie jest ironiczne, biorąc pod uwagę filozofię Pythona, że ​​ma tylko jeden oczywisty sposób na zrobienie czegoś. – sykora

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

Przekaż swoje punkty końcowe w postaci listy w endpoints, tak:

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

Edit:

Powyższe jest przeszukiwanie liniowe. Odpowiedź Glenna Maynarda będzie lepsza, ponieważ wykorzystuje algorytm bisekcji.

+0

Przerwij "poprzednią" kaparę; jest dość niepotrzebny. –

+0

Tak, masz rację, domyślam się, że oryginalny kod "zainspirował" mnie do tego. Przy okazji, twoje użycie nakazu może dla niektórych wydawać się nieco szorstkie. – Steef

+0

@Steef: Możesz rozważyć pokorną sugestię, że możesz w wolnym czasie powtórzyć swoją odpowiedź, zauważ, że ** twoja odpowiedź nadal zawiera zbędny wiersz kodu **, a w pełni czasu, akcyzuj to samo. –

0

Innym sposobem ...

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

To jest rzeczywiście dość straszne. Bez wymóg nie mają sztywno, to powinno być napisane tak:

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 

Oto przykłady tworzenia funkcji wyszukiwania, zarówno liniowych i stosując wyszukiwanie binarne, z wymogiem no-hardcodings spełnione, a kilka kontroli poprawności na dwóch stołach:

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

Podoba mi się ten jeden lepszy niż ten, który ma najwięcej głosów ze względu na bardziej uogólnioną/nieskodowaną formę i dlatego, że jest bardziej dogłębny. – JAB