0

Talking Python 3 here.

I'm looking to round a number to a given set of values which can vary

Assume value_set = [x, y, z] and for the sake of the example x, y, z = 1, 3.12, 4 I'm looking for a function that will round a given float to the closest number

custom_round(0) --> 1

custom_round(2.7) --> 3.12

Notice that it should be generic enough that value_set length will vary also

bluesummers
  • 11,365
  • 8
  • 72
  • 108

2 Answers2

5

You can use the min function in order to find the minimum in your list when the key is the absolute value of x-n (x is each item in the list).

value_set = [1, 3.12, 4]

def return_closest(n):
  return min(value_set, key=lambda x:abs(x-n))

number_to_check = 3
print (return_closest(number_to_check))

>>> 3.12
omri_saadon
  • 10,193
  • 7
  • 33
  • 58
0

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.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555