2012-03-26 8 views
5

Mam listę Pythona predefiniowanych liczb:Python: Okrągły do ​​następnego predefiniowanego całkowitą w liście

intvals = [5000, 7500, 10000, 20000, 30000, 40000, 50000] 

muszę zaokrąglić w dół i w górę do następnej niższej/wyższej wartości na liście. Na przykład, biorąc pod uwagę numer 8000, wynikiem powinno być [7500, 10000]. Dla 42000 powinno być [40000, 50000]. Zastanawiam się, czy istnieje prosty sposób na zrobienie tego.

Mój pomysł polegałby na utworzeniu funkcji, która ma dwie pętle - jedną, która zmniejsza wartość -1, dopóki nie znajdzie jednego na liście, i która zwiększy wartość o 1, dopóki nie znajdzie wyższego dopasowania. To zadziała, ale może jest lepsze rozwiązanie?

Odpowiedz

15

Jest to idealne rozwiązanie dla bisect.bisect_right() i bisect.bisect_left().

Oto przykład kodu, dla którego można rozszerzyć o:

import bisect 

def get_interval(x): 
    intvals = [5000, 7500, 10000, 20000, 30000, 40000, 50000] 
    i = bisect.bisect_right(intvals,x) 
    return intvals[i-1:i+1] 

print get_interval(5500) 

""" 
>>> 
[5000, 7500] 
""" 

Technika ta jest szybka, ponieważ korzysta przeszukiwanie binarne (tak logn zamiast N wyszukiwań)

+0

To jest niesamowite. –

+1

W szczególności będziesz potrzebować kodu do obsługi przypadków krawędzi (czy zdefiniowano 'get_interval (5)?) –

+0

Dziękuję za szybką odpowiedź. Dokładnie to, czego potrzebuję! Nigdy nie słyszałem o module bisect – Daniel

2

bisect jest zbudowany do wyszukiwania w ten sposób.

>>> intvals[bisect.bisect(intvals, 8000)] 
10000 
>>> intvals[bisect.bisect(intvals, 42000)] 
50000 
5

można użyć modułu bisect . Być może będziesz musiał poprawić przykład, aby zaspokoić swoje potrzeby dotyczące granic.

>>> import bisect 
>>> def RoundUpDown(rangeList,num): 
    beg = bisect.bisect_right(rangeList,num) 
    if rangeList[beg-1] == num: #Handle Perfect Hit Edge Case 
     return [num,num] 
    elif not beg: #Left Edge Case 
     return [None,rangeList[0]] 
    elif beg == len(rangeList): #Right Edge Case 
     return [rangeList[-1],None] 
    else: 
     return rangeList[beg-1:beg+1] 


>>> RoundUpDown([5000, 7500, 10000, 20000, 30000, 40000, 50000],41000) 
[40000, 50000] 
>>> RoundUpDown([5000, 7500, 10000, 20000, 30000, 40000, 50000],5000) 
[5000, 5000] 
>>> RoundUpDown([5000, 7500, 10000, 20000, 30000, 40000, 50000],500) 
[None, 5000] 
>>> RoundUpDown([5000, 7500, 10000, 20000, 30000, 40000, 50000],50000) 
[50000, 50000] 
>>> RoundUpDown([5000, 7500, 10000, 20000, 30000, 40000, 50000],51000) 
[50000, None] 
>>> RoundUpDown([5000, 7500, 10000, 20000, 30000, 40000, 50000],7500) 
[7500, 7500] 
>>> 
0

Ustaw "minDiff" int na maxint, a "minIndex" na -1. Iteruj listę i oblicz wartość bezwzględną różnicy między indeksowaną wartością listy a celem. Jeśli ta wartość jest mniejsza od wartości minDiff, należy ją załadować do minDiff i zapisać indeks w minIndex. Jeśli wartość jest większa niż wartość minDiff, należy zwrócić wartość minIndex. Uwaga - zakłada, że ​​lista jest posortowana. Jeśli lista nie jest posortowana, będziesz musiał powtórzyć całą listę, aby upewnić się, że znalazłeś minimalną różnicę.

0

Jeśli odstępy nie są zbyt duże i nie jesteś zbyt zaniepokojeni zużycie pamięci, a następnie następujące rozwiązanie będzie szybko:

intvals = [5000, 7500, 10000, 20000, 30000, 40000, 50000] 

pairs = zip(intvals,intvals[1:]) 
d = {} 
for start,end in pairs: 
    for i in range(start,end+1): 
     d[i] = (start,end) 

def get_interval(i): 
    if i in d: 
     return d[i] 
    else: 
     return -1 

print get_interval(5500) 

""" 
>>> 
(5000, 7500) 
""" 

uwaga nie mam martwi co get_interval (7500) powinien powrócić (chociaż 7500 jest w dwóch odstępach czasu), ale możesz go skorygować tak, jak chcesz.

Powiązane problemy