Учитывая, что вам нужно выполнять поиск довольно часто, мы можем сделать это алгоритмом O (log n) , сначала сохранив данные в отсортированном списке:
from operator import itemgetter
ks = sorted(A.items(), key=itemgetter(1))
vs = list(map(itemgetter(1), ks))
Тогда для каждого элемента мы можем использовать точку bisect.bisect_left
, чтобы определить точку вставки.Затем мы можем проверить два окружающих значения, проверить наименьшее и вернуть соответствующий ключ.Также возможно, что
from bisect import bisect_left
from operator import itemgetter
def closests(v):
idx = bisect_left(vs, v)
i, j = max(0, idx-1), min(idx+2, len(ks))
part = ks[i:j]
return sorted([[*pi, abs(pi[-1]-v)] for pi in part], key=itemgetter(-1))[:2]
Вышеприведенное может не выглядеть улучшением, но здесь мы всегда будем оценивать самое большее три элемента в sorted(..)
, и bisect_left
будетоцените логарифмическое количество элементов.
Например:
>>> closests(1)
[['ppp', 3.2, 2.2], ['jlkljkjlk', 9.23, 8.23]]
>>> closests(3.2)
[['ppp', 3.2, 0.0], ['jlkljkjlk', 9.23, 6.03]]
>>> closests(5)
[['ppp', 3.2, 1.7999999999999998], ['jlkljkjlk', 9.23, 4.23]]
>>> closests(9.22)
[['jlkljkjlk', 9.23, 0.009999999999999787], ['abc', 12.3, 3.08]]
>>> closests(9.24)
[['jlkljkjlk', 9.23, 0.009999999999999787], ['abc', 12.3, 3.0600000000000005]]
Фаза "загрузки", таким образом, занимает O (n log n) (с n количеством элементов).Затем, если мы обобщим описанный выше метод для извлечения k элементов (путем увеличения среза), потребуется O (log n + k log k) , чтобы выполнить поиск.