I am interested to take the index of a generic list "L" of values contained in another list, called "target". It seems simple, but if I have the target list with slightly different values, I do not know how to consider this difference. For instance, if in the "L" list I have a value that is 1.9, and in the target the value is 1.89, I want to take the index of 1.9, since it is close to 1.89. How can I do this?
L = [0.4,0.5,0.55,0.78,0.9,1.1,1.8,1.9]
target = [0.55,0.9,1.09,1.89]
index = []
for i in target:
index.append(L.index(i))
print(index)
Expected output: [2,4,5,7]
Thanks in advance!
CodePudding user response:
You could use math.isclose:
import math
L = [0.4, 0.5, 0.55, 0.78, 0.9, 1.1, 1.8, 1.9]
target = [0.55, 0.9, 1.09, 1.89]
index = [i for i, e in enumerate(L) if any(math.isclose(e, t, abs_tol=0.05) for t in target)]
print(index)
Output
[2, 4, 5, 7]
The computational complexity of the above approach is O(nm)
, where n
and m
are the lengths of the lists L and target. Additionally you could sort target
to do it in O((n m)logn)
:
def is_close_to_any(e, tgt):
import bisect
"""Finds if any values are close in O(log n)"""
point_before_insertion = max(0, bisect.bisect(tgt, e) - 1)
# find two closest points
values = tgt[point_before_insertion:point_before_insertion 2]
# return if any of the two is close
return any(math.isclose(e, t, abs_tol=0.05) for t in values)
target = sorted(target)
index = [i for i, e in enumerate(L) if is_close_to_any(e, target)]
print(index)
Output (using sorted and bisect)
[2, 4, 5, 7]
CodePudding user response:
If L
is sorted, you can use bisect
to find the closest value:
from bisect import bisect
def find_closest(L, x):
index = bisect(L, x)
if index == 0: return 0
elif index == len(L): return index-1
elif x - L[index-1] > L[index] - x: return index
else: return index-1
[find_closest(L, x) for x in target]
# [2, 4, 5, 7]
CodePudding user response:
Python's min
of the abs
distance over zipped values and indices.
L = [0.4,0.5,0.55,0.78,0.9,1.1,1.8,1.9]
target = [0.55,0.9,1.09,1.89]
[min(zip(L, range(len(L))), key=lambda x:abs(x[0]-i))[1] for i in target]
Output
[2, 4, 5, 7]