Home > OS >  Python - Take the index of slightly different values
Python - Take the index of slightly different values

Time:10-01

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]
  • Related