I am trying to get both the closest value and its index in a sorted list in python.
In MATLAB this is possible with:
[closest_val,index] = min(abs(array - target))
I was wondering if there is a similar way this can be implemented in python.
I've seen posts which do one or the other, but I haven't seen both done together.
Link to finding closest value in list post.
解决方案
bisect wasn't used in the linked question because the list was not sorted. Here, we don't have the same problem, and we can use bisect for the speed it provides:
import bisect
def find_closest_index(a, x):
i = bisect.bisect_left(a, x)
if i >= len(a):
i = len(a) - 1
elif i and a[i] - x > x - a[i - 1]:
i = i - 1
return (i, a[i])
find_closest_index([1, 2, 3, 7, 10, 11], 0) # => 0, 1
find_closest_index([1, 2, 3, 7, 10, 11], 7) # => 3, 7
find_closest_index([1, 2, 3, 7, 10, 11], 8) # => 3, 7
find_closest_index([1, 2, 3, 7, 10, 11], 9) # => 4, 10
find_closest_index([1, 2, 3, 7, 10, 11], 12) # => 5, 11
EDIT: In case of descending array:
def bisect_left_rev(a, x, lo=0, hi=None):
if lo < 0:
raise ValueError('lo must be non-negative')
if hi is None:
hi = len(a)
while lo < hi:
mid = (lo+hi)//2
if a[mid] > x: lo = mid+1
else: hi = mid
return lo
def find_closest_index_rev(a, x):
i = bisect_left_rev(a, x)
if i >= len(a):
i = len(a) - 1
elif i and a[i] - x < x - a[i - 1]:
i = i - 1
return (i, a[i])
find_closest_index_rev([11, 10, 7, 3, 2, 1], 0) # => 5, 1
find_closest_index_rev([11, 10, 7, 3, 2, 1], 7) # => 2, 7
find_closest_index_rev([11, 10, 7, 3, 2, 1], 8) # => 2, 7
find_closest_index_rev([11, 10, 7, 3, 2, 1], 9) # => 1, 10
find_closest_index_rev([11, 10, 7, 3, 2, 1], 12) # => 0, 11