You can do this by first sorting the list, and then use binary search:
from bisect import bisect_left
class CustomRound:
def __init__(self,iterable):
self.data = sorted(iterable)
def __call__(self,x):
data = self.data
ndata = len(data)
idx = bisect_left(data,x)
if idx <= 0:
return data[0]
elif idx >= ndata:
return data[ndata-1]
x0 = data[idx-1]
x1 = data[idx]
if abs(x-x0) < abs(x-x1):
return x0
return x1
You can than construct your CustomRound
like:
values = [1,3.12,4]
custom_round = CustomRound(values)
and simply call it:
>>> custom_round(0)
1
>>> custom_round(0.5)
1
>>> custom_round(1.5)
1
>>> custom_round(2.5)
3.12
>>> custom_round(3.12)
3.12
>>> custom_round(3.9)
4
>>> custom_round(4.1)
4
>>> custom_round(4.99)
4
This approach will work in O(log n) for rounding and O(n log n) for construction. So you will invest some additional time to construct the custom_round
, but if you call it often, it will eventually pay off in rounding individual numbers.