Reputation: 37
I'm trying to find a way to snap or quantize numbers to specific values after a math operation and don't really know the best way to approach the problem.
A specific example:
I have a list of numbers that I want to be my master numbers - 5, 10, 30, 60, 120, 180
I have a list of numbers that are currently inputted - 10, 20, 60, 120
Now I want to multiply all the inputted numbers by 2, and have them snap (or quantize/get rounded to) the nearest of my master numbers.
So a number like 10, once multiplied by two, I'd like to have it snap to 30. I dont think it's a big problem for the top or bottom because I think I can use math.ceil and math.floor to contain the ends. Similarly I'd like 20 to be rounded to 30 as well (20*2=40, rounded down as 30 is closer than 60).
I saw a similar question in regards to rounding to 10s, 100s, etc, but can't really figure out how to apply the answer there, as I'm still relatively new! : )
Upvotes: 1
Views: 1296
Reputation: 154866
Use the bisect
module to quickly pinpoint the desired quantity:
import bisect
def quantize(num, quant):
mids = [(quant[i] + quant[i + 1]) / 2.0
for i in xrange(len(quant) - 1)]
ind = bisect.bisect_right(mids, num)
return quant[ind]
quantnum = [5, 10, 30, 60, 120, 180]
inputnum = [10, 20, 60, 120]
for n in inputnum:
print quantize(2 * n, quantnum)
# Output:
#30
#30
#120
#180
Midpoints are rounded to the larger quantity; change bisect_right
to bisect_left
to round to the smaller one instead.
For simplicity, this implementation recreates the mids
list each time it is called. An efficient implementation would reuse the midpoints, and would run with O(log n)
worst-case complexity.
Upvotes: 3
Reputation: 250881
For element x
of input
find the absolute difference of x*2
with each element of master
and x*2
, and then the minimum of that new list will be the rounded number.
for ex. for for 20 from the input list, the list of absolute differences is going to be:
[abs(5-40),abs(10-40),abs(30-40),abs(60-40),abs(120-40),abs(180-40)]
which results in [35,30,10,20,80,140]
, and the minimum difference came for 3rd
element ,i.e 30
of master
list
In [14]: inp=[10, 20, 60, 120,17,27,50]
In [15]: master=[5, 10, 30, 60, 120, 180]
In [16]: [min(master,key=lambda y:abs(y-x*2)) for x in inp]
Out[16]: [10, 30, 120, 180, 30, 60, 120]
Upvotes: 2