Python:从给定的输入键中找到字典中最接近的键

时间:2011-10-28 20:28:53

标签: python algorithm dictionary

我有一个字典数据.. 我接受用户的输入,它可以是任何东西.. 我正在努力做到以下几点。 如果密钥存在则冷却..从字典中获取值。 如果没有,则获取最近的(在数字意义上)。 例如..如果输入键是200 钥匙就像:....

197,202,208...

然后202可能是最接近200的钥匙。 现在,从算法的角度来看。它直截了当..但有一种pythonic方式来做到这一点? 感谢

6 个答案:

答案 0 :(得分:25)

dict键没有特别的顺序,这个问题变得更加困难。如果你可以玩你如何制作字典以便他们按顺序(如你的例子)并使用python> = 2.7,你可以使用OrderedDictbisect来快速闪电。

import collections
a = collections.OrderedDict()
for i in range(100):
    a[i] = i

import bisect
ind = bisect.bisect_left(a.keys(), 45.3)

然后你只需要检查元素indind-1,看看哪个更接近,从而减少计算量。


正如Steven G在下面指出的那样,在Python3中,.keys()不仅仅是一个列表,必须改为一个。

bisect.bisect_left(list(a.keys()), 45.3)

答案 1 :(得分:23)

这是你在一行上的功能:

data.get(num, data[min(data.keys(), key=lambda k: abs(k-num))])

编辑:当键在dict使用时不评估min:

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 :(得分:14)

不要使用OrderedDict和bisect,而应考虑SortedDict模块中的sortedcontainers类型。它是一个纯Python和fast-as-C implementation的排序列表,排序的dict和排序的集合类型,具有100%的测试覆盖率和数小时的压力。

使用SortedDict,您可以将所需的键平分。例如:

from itertools import islice
from sortedcontainers import SortedDict

def closest(sorted_dict, key):
    "Return closest key in `sorted_dict` to given `key`."
    assert len(sorted_dict) > 0
    keys = list(islice(sorted_dict.irange(minimum=key), 1))
    keys.extend(islice(sorted_dict.irange(maximum=key, reverse=True), 1))
    return min(keys, key=lambda k: abs(key - k))

closest函数使用SortedDict.irange创建最接近给定键的键的迭代器。密钥以log(N)运行时复杂度被分成两部分。

>>> sd = SortedDict({-3: 'a', 0: 'b', 2: 'c'})
>>> for num in range(-5, 5):
...     key = closest(sd, num)
...     print('Given', num, ', closest:', key)
Given -5 , closest: -3
Given -4 , closest: -3
Given -3 , closest: -3
Given -2 , closest: -3
Given -1 , closest: 0
Given 0 , closest: 0
Given 1 , closest: 2
Given 2 , closest: 2
Given 3 , closest: 2
Given 4 , closest: 2

Pythonic使用PyPI!

答案 3 :(得分:1)

如果你拥有的只是一本Python字典,那么你不能比检查字典中的所有条目做得更好(如Will的答案)。但是,如果您希望更有效地找到最接近的密钥(即O(log N)而不是O(N)),则需要某种平衡树。

不幸的是,我不相信Python在其标准库中有这样的数据结构 - 因为Pythonic的方法是使用dict代替。所以,如果你希望在一张大地图上做出很多这样的查询,你最好的选择可能就是找到一个扩展库,甚至自己动手...

答案 4 :(得分:0)

这应该做你想要的(减去从钥匙上取下来,但你可以弄清楚:)。

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来自this question

答案 5 :(得分:0)

使用sortedcontainers.SortedDict,您可以这样做:

def closest_item(sdict, key):
    if len(sdict) == 0:
        raise KeyError('No items in {sdict.__class__.__name__}')

    if len(sdict) == 1:
        return next(iter(sdict.items()))

    idx_before = next(sdict.irange(minimum=key), None)
    idx_after = next(sdict.irange(maximum=key, reverse=True), None)

    if idx_before is None:
        idx = idx_after

    elif idx_after is None:
        idx = idx_before
    else:
        idx = min(idx_before, idx_after, key=lambda x: abs(x - key))

    return idx, sdict[idx]