'Python: Round to next predefined integer in list
I have a Python list of predefined integers:
intvals = [5000, 7500, 10000, 20000, 30000, 40000, 50000]
I need to round down and up to the next lower/higher value in the list. So for example, given the number 8000, the result should be [7500, 10000]. For 42000, it should be [40000, 50000]. I am wondering if there is an easy way to do it.
My idea would be to create a function that has two loops - one that decreases a value -1 until it finds one in the list, and one that increases the value by 1 until it finds the higher match. This would work but maybe there is a better solution?
Solution 1:[1]
You can use the bisect module. You may have to tweak the example to satisfy your boundary case needs.
>>> 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]
>>>
Solution 2:[2]
bisect is built for searching like this.
>>> intvals[bisect.bisect(intvals, 8000)]
10000
>>> intvals[bisect.bisect(intvals, 42000)]
50000
Solution 3:[3]
Set a 'minDiff' int to maxint and an 'minIndex' to -1. Iterate the list and calculate the absolute value of the difference between the indexed list value and the target. If this value is less than the minDiff, load it into the minDiff and store the index in minIndex. If the value is more than the minDiff, return the minIndex. Note - assumes list is sorted. If list is not sorted, you will have to iterate the entire list to ensure you have found the minimum difference.
Solution 4:[4]
If you're intervals aren't too large and you're not too worried about memory consumption, then the following solution will be fast:
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)
"""
note I haven't worried about what get_interval(7500) should return (although 7500 is in two intervals .. ) but you can correct it to be what you desire.
Solution 5:[5]
Just a quick answer for the question in the headline: "Python: Round to next predefined integer in list"
I wanted a fast one-line-solution without additional libraries. (I'm already using numpy.) Based on the mentioned setting:
import numpy as np
x = 42000
intvals = np.array([5000, 7500, 10000, 20000, 30000, 40000, 50000])
The solution is:
intvals[np.argmin(np.abs(x - intvals))]
Or used on column "value" of a pandas.DataFrame df:
df['value_adapted'] = df.value.apply(lambda x: intvals[np.argmin(np.abs((x - intvals)))])
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Ignacio Vazquez-Abrams |
| Solution 3 | Martin James |
| Solution 4 | robert king |
| Solution 5 | Thomas R |
