I was wondering if it is possible to find the closest element in a List
for a element that is not there.
For example if we had the valu
Just thinking off the top of my head, if you need to find all closest values in a sorted list, you can find a closest value, then find all values with the same distance away from the target. Here, I use binary search 3 times:
In Python:
def closest_value(arr, target):
def helper(arr, target, lo, hi, closest_so_far):
# Edge case
if lo == hi:
mid = lo
if abs(arr[mid] - target) < abs(arr[closest_so_far] - target):
closest_so_far = mid
return closest_so_far
# General case
mid = ((hi - lo) >> 1) + lo
if arr[mid] == target:
return mid
if abs(arr[mid] - target) < abs(arr[closest_so_far] - target):
closest_so_far = mid
if arr[mid] < target:
# Search right
return helper(arr, target, min(mid + 1, hi), hi, closest_so_far)
else:
# Search left
return helper(arr, target, lo, max(mid - 1, lo), closest_so_far)
if len(arr) == 0:
return -1
return helper(arr, target, 0, len(arr) - 1, arr[0])
arr = [0, 10, 14, 27, 28, 30, 47]
attempt = closest_value(arr, 26)
print(attempt, arr[attempt])
assert attempt == 3
attempt = closest_value(arr, 29)
print(attempt, arr[attempt])
assert attempt in (4, 5)
def closest_values(arr, target):
def left_helper(arr, target, abs_diff, lo, hi):
# Base case
if lo == hi:
diff = arr[lo] - target
if abs(diff) == abs_diff:
return lo
else:
return lo + 1
# General case
mid = ((hi - lo) >> 1) + lo
diff = arr[mid] - target
if diff < 0 and abs(diff) > abs_diff:
# Search right
return left_helper(arr, target, abs_diff, min(mid + 1, hi), hi)
elif abs(diff) == abs_diff:
# Search left
return left_helper(arr, target, abs_diff, lo, max(mid - 1, lo))
else:
# Search left
return left_helper(arr, target, abs_diff, lo, max(mid - 1, lo))
def right_helper(arr, target, abs_diff, lo, hi):
# Base case
if lo == hi:
diff = arr[lo] - target
if abs(diff) == abs_diff:
return lo
else:
return lo - 1
# General case
mid = ((hi - lo) >> 1) + lo
diff = arr[mid] - target
if diff < 0 and abs(diff) > abs_diff:
# Search right
return right_helper(arr, target, abs_diff, min(mid + 1, hi), hi)
elif abs(diff) == abs_diff:
# Search right
return right_helper(arr, target, abs_diff, min(mid + 1, hi), hi)
else:
# Search left
return right_helper(arr, target, abs_diff, lo, max(mid - 1, lo))
a_closest_value = closest_value(arr, target)
if a_closest_value == -1:
return -1, -1
n = len(arr)
abs_diff = abs(arr[a_closest_value] - target)
left = left_helper(arr, target, abs_diff, 0, a_closest_value)
right = right_helper(arr, target, abs_diff, a_closest_value, n - 1)
return left, right
arr = [0, 10, 14, 27, 27, 29, 30]
attempt = closest_values(arr, 28)
print(attempt, arr[attempt[0] : attempt[1] + 1])
assert attempt == (3, 5)
attempt = closest_values(arr, 27)
print(attempt, arr[attempt[0] : attempt[1] + 1])
assert attempt == (3, 4)