[英]finding index of an item closest to the value in a list that's not entirely sorted
作為一個例子,我的列表是:
[25.75443, 26.7803, 25.79099, 24.17642, 24.3526, 22.79056, 20.84866, 19.49222, 18.38086, 18.0358, 16.57819, 15.71255, 14.79059, 13.64154, 13.09409, 12.18347, 11.33447, 10.32184, 9.544922, 8.813385, 8.181152, 6.983734, 6.048035, 5.505096, 4.65799]
我正在尋找最接近11.5
的值的索引。 我嘗試過其他方法,如二進制搜索和bisect_left
但它們不起作用。
我無法對此數組進行排序,因為該值的索引將用於類似的數組以獲取該索引處的值。
請嘗試以下方法:
min(range(len(a)), key=lambda i: abs(a[i]-11.5))
例如:
>>> a = [25.75443, 26.7803, 25.79099, 24.17642, 24.3526, 22.79056, 20.84866, 19.49222, 18.38086, 18.0358, 16.57819, 15.71255, 14.79059, 13.64154, 13.09409, 12.18347, 11.33447, 10.32184, 9.544922, 8.813385, 8.181152, 6.983734, 6.048035, 5.505096, 4.65799]
>>> min(range(len(a)), key=lambda i: abs(a[i]-11.5))
16
或者獲取索引和值:
>>> min(enumerate(a), key=lambda x: abs(x[1]-11.5))
(16, 11.33447)
import numpy as np
a = [25.75443, 26.7803, 25.79099, 24.17642, 24.3526, 22.79056, 20.84866, 19.49222, 18.38086, 18.0358, 16.57819, 15.71255, 14.79059, 13.64154, 13.09409, 12.18347, 11.33447, 10.32184, 9.544922, 8.813385, 8.181152, 6.983734, 6.048035, 5.505096, 4.65799]
index = np.argmin(np.abs(np.array(a)-11.5))
a[index] # here is your result
如果a已經是數組,則可以省略相應的轉換。
怎么樣:你壓縮兩個列表,然后對結果進行排序?
如果您無法對數組進行排序,則無法快速找到最近的項目 - 您必須遍歷所有條目。
有一個解決方法,但它有相當多的工作:編寫一個排序算法,對數組進行排序,並(同時)更新第二個數組,告訴你在數組排序之前這個條目的位置。
這樣,您可以使用二進制搜索來查找最近條目的索引,然后使用此索引使用“索引數組”查找原始索引。
[編輯]使用zip()
,這很容易實現:
array_to_sort = zip( original_array, range(len(original_array)) )
array_to_sort.sort( key=i:i[0] )
現在您可以二進制搜索該值(使用item[0]
)。 item[1]
會給你原始索引。
通過所有項目只是線性的。 如果你要對陣列進行排序會更糟糕。
我沒有看到保持額外的deltax
(到目前為止的最小差異)和idx
(該元素的索引)的問題,只是循環一次通過列表。
請記住,如果空間不重要,您可以通過創建排序索引的輔助列表來對任何列表進行排序,而無需移動內容。
還要記住,如果你只是查看一次,那么你只需要遍歷列表O(n)中的每個元素。 (如果多次,那么您可能希望以后進行排序以提高效率)
如果你經常搜索一個很長的列表,那么min
刻度非常差(O(n ^ 2),如果你將一些搜索附加到搜索列表中,我認為)。
Bisect是你的朋友。 這是我的解決方案。 它縮放O(n * log(n)):
class Closest:
"""Assumes *no* redundant entries - all inputs must be unique"""
def __init__(self, numlist=None, firstdistance=0):
if numlist == None:
numlist=[]
self.numindexes = dict((val, n) for n, val in enumerate(numlist))
self.nums = sorted(self.numindexes)
self.firstdistance = firstdistance
def append(self, num):
if num in self.numindexes:
raise ValueError("Cannot append '%s' it is already used" % str(num))
self.numindexes[num] = len(self.nums)
bisect.insort(self.nums, num)
def rank(self, target):
rank = bisect.bisect(self.nums, target)
if rank == 0:
pass
elif len(self.nums) == rank:
rank -= 1
else:
dist1 = target - self.nums[rank - 1]
dist2 = self.nums[rank] - target
if dist1 < dist2:
rank -= 1
return rank
def closest(self, target):
try:
return self.numindexes[self.nums[self.rank(target)]]
except IndexError:
return 0
def distance(self, target):
rank = self.rank(target)
try:
dist = abs(self.nums[rank] - target)
except IndexError:
dist = self.firstdistance
return dist
像這樣使用它:
a = [25.75443, 26.7803, 25.79099, 24.17642, 24.3526, 22.79056, 20.84866,
19.49222, 18.38086, 18.0358, 16.57819, 15.71255, 14.79059, 13.64154,
13.09409, 12.18347, 1.33447, 10.32184, 9.544922, 8.813385, 8.181152,
6.983734, 6.048035, 5.505096, 4.65799]
targets = [1.0, 100.0, 15.0, 15.6, 8.0]
cl = Closest(a)
for x in targets:
rank = cl.rank(x)
print("Closest to %5.1f : rank=%2i num=%8.5f index=%2i " % (x, rank,
cl.nums[rank], cl.closest(x)))
將輸出:
Closest to 1.0 : rank= 0 num= 1.33447 index=16
Closest to 100.0 : rank=25 num=26.78030 index= 1
Closest to 15.0 : rank=12 num=14.79059 index=12
Closest to 15.6 : rank=13 num=15.71255 index=11
Closest to 8.0 : rank= 5 num= 8.18115 index=20
和:
cl.append(99.9)
x = 100.0
rank = cl.rank(x)
print("Closest to %5.1f : rank=%2i num=%8.5f index=%2i " % (x, rank,
cl.nums[rank], cl.closest(x)))
輸出:
Closest to 100.0 : rank=25 num=99.90000 index=25
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.