user479053
user479053

Reputation:

Python find closest decimal match

I have a list as follows:

CHOICES = (
    ('8.25', '0'),
    ('7.35', '1'),
    [...]
)

The model I use stores the first value in the tuple (e.g. 8.25 -incidentally, in mm). I need a function that takes any given decimal value (potentially not in the list) and matches it with the closest value on the CHOICES list, to return the relevant whole number.

So example input could be 8.11 which would return 0 or 7.30 which would return 1 etc.

Upvotes: 0

Views: 1751

Answers (3)

S.Lott
S.Lott

Reputation: 391952

This works pretty well

distances = [ (abs(target-float(v)), m) for v,m in CHOICES ]
value, match = min( distances )

Since you use the word, "decimal", perhaps you mean this.

distances = [ (abs(target-decimal.Decimal(v)), m) for v,m in CHOICES ]

Not that it matters much.

Upvotes: 0

vartec
vartec

Reputation: 134631

Unless your values are sorted and assuming the number of the choices is not huge:

result = sorted([(math.abs(k - input_val),v) for (k,v) in choices])[0]

Otherwise sort the choices once and use binary search (bisect), as suggested in other answer. It'd look like:

#do this part only once
choices_dict = dict(choices)
sorted_keys = sorted([ float(k) for (k,v) in choices])
#...
l,r = bisect_left(input_value,sorted_keys), bisect_right(input_value,sorted_keys)
k = l if math.abs(input_value-l)<math.abs(input_value-r) else r
result = choices_dict(str(k))

Upvotes: 4

S.Lott
S.Lott

Reputation: 391952

http://docs.python.org/library/bisect.html

Read the examples at the end.

Upvotes: 2

Related Questions