Python: найти ближайший ключ в словаре от данного ключа ввода
У меня есть данные в виде словаря.
NOw Я беру данные от пользователя, и это может быть что угодно..
И я пытаюсь сделать следующее.
Если ключ существует, тогда cool... выберите значение из словаря.
если нет, то выберите ближайший (в цифровом смысле).
Например, если входной ключ равен 200
и клавиши такие как:....
197,202,208...
Тогда, вероятно, 202 является ближайшим ключом к 200..
Теперь, с точки зрения алгоритма. его прямо вперед.. но есть ли питонический способ сделать это?
Благодаря
Ответы
Ответ 1
здесь ваша функция в одной строке:
data.get(num, data[min(data.keys(), key=lambda k: abs(k-num))])
edit: чтобы не оценивать min, когда ключ находится в использовании dict:
data[num] if num in data else data[min(data.keys(), key=lambda k: abs(k-num))]
или если все значения в data
оцениваются до True
, вы можете использовать:
data.get(num) or data[min(data.keys(), key=lambda k: abs(k-num))]
Ответ 2
Эта проблема намного сложнее, чем клавиши dict, не имеющие особого порядка. Если вы можете играть с тем, как вы делаете dict, чтобы они были в порядке (например, ваш пример) и использовали python >= 2.7, вы можете использовать OrderedDict и bisect, чтобы сделать это молниеносно.
import collections
a = collections.OrderedDict()
for i in range(100):
a[i] = i
import bisect
ind = bisect.bisect_left(a.keys(), 45.3)
Тогда вам нужно только проверить элемент ind
и ind-1
, чтобы увидеть, что ближе, тем самым делая намного меньше вычислений.
Как указано ниже, Стивен G, в Python3,.keys() - это не просто список и его необходимо изменить на один.
bisect.bisect_left(list(a.keys()), 45.3)
Ответ 3
Вместо использования OrderedDict и bisect рассмотрите тип SortedDict в модуле sortedcontainers, Это версия pure-Python и fast-as-C отсортированного списка, dict и заданных типов со 100% -ным охватом тестирования и часами стресса.
С помощью SortedDict вы можете делить пополам нужную клавишу. Например:
from sortedcontainers import SortedDict
sd = SortedDict((key, value) for key, value in data)
# Bisect for the index of the desired key.
index = sd.bisect(200)
# With that index, lookup the key.
key = sd.iloc[index]
# You can also look ahead or behind to find the nearest key.
behind = sd.iloc[index - 1]
ahead = sd.iloc[index + 1]
Это Pythonic для использования PyPI!
Ответ 4
Если все, что у вас есть, это словарь Python, вы не можете сделать лучше, чем проверка всех записей в словаре (как в ответе "Ответ" ). Однако, если вы хотите найти ближайший ключ более эффективно, чем это (т.е. В O(log N)
вместо O(N)
), вам нужно какое-то сбалансированное дерево.
К сожалению, я не считаю, что Python имеет такую структуру данных в своей стандартной библиотеке, что и Pythonic - это использовать вместо этого dict. Итак, если вы ожидаете сделать много таких запросов на большой карте, лучшим выбором может быть поиск библиотеки расширений или даже сворачивание собственного...
Ответ 5
Это должно делать то, что вы хотите (минус получить его от ключа, но вы можете понять это:).
f = lambda a,l:min(l,key=lambda x:abs(x-a))
numbers = (100, 200, 300, 400)
num = int(raw_input())
print 'closest match:', f(num, numbers)
Примечание: f
находится в этом вопросе.