我有一个字典,其中键是整数。我有另一个整数。我想找到与dict中最接近给定整数的键对应的值。有没有一种有效的方法呢?
也许不同的数据结构(二叉树)会更有效率?
答案 0 :(得分:1)
dd = {2:'x', 6:'y', 100000:'z', 77:'w'}
ikey = 99
low = max([d for d in dd if d<= ikey])
high = min([d for d in dd if d>= ikey])
nearkey = low if ikey - low <= high - ikey else high
nearkey
77
答案 1 :(得分:1)
二进制搜索树
你对二叉搜索树的建议让我想到了如何实现它,所以我继续前进并做到了。如果我没有弄错的话,这会在查找期间提供O(log n)复杂度,但需要更多的设置时间(线性而不是常数),这意味着它只在更多读取密集的情况下才是最佳的。
from math import inf
class RangeMap:
def __init__(self, dictionary, minimum=-inf, maximum=inf):
assert dictionary
self._dictionary = dictionary
self.min, self.max = minimum, maximum
self._generate_tree()
def __delitem__(self, key):
del self._dictionary[key]
self._generate_tree()
def __getitem__(self, item):
current = self._tree
while current:
if item < current.lower:
current = current.before
elif item <= current.upper:
return current.value
else:
current = current.after
raise Exception("Tree not constructed properly")
def __setitem__(self, key, value):
self._dictionary[key] = value
self._generate_tree()
def _generate_tree(self):
range_mapping = [(((p + c) / 2, (c + n) / 2), self._dictionary[c])
for p, c, n in self._iterate_keys()]
self._tree = RangeMap.Node(range_mapping)
def _iterate_keys(self):
keys = sorted(self._dictionary.keys())
return zip([self.min] + keys[:-1], keys, keys[1:] + [self.max])
class Node:
def __init__(self, range_mapping):
assert range_mapping
middle = len(range_mapping) // 2
(self.lower, self.upper), self.value = range_mapping[middle]
before, after = range_mapping[:middle], range_mapping[middle + 1:]
self.before = RangeMap.Node(before) if before else None
self.after = RangeMap.Node(after) if after else None
你会这样使用它(在距离上的关系[我完全达到的决定所以__getitem__不会打破无限 - 将这个改变__getitem__中的<=
改为<
] ):
>>> dictionary = {
... 4: 'four',
... 8: 'eight',
... 15: 'fifteen',
... 16: 'sixteen',
... 23: 'twenty-three',
... 42: 'forty-two'
... }
>>> range_map = RangeMap(dictionary)
>>> range_map[11]
'eight'
>>> range_map[12]
'fifteen'
>>> range_map[15]
'fifteen'
>>> range_map[16]
'sixteen'
>>> range_map[19]
'sixteen'
我兄弟的想法
我问我的非程序员兄弟他将如何解决这个问题,他想出了从你想要的钥匙向外检查(我把它放到代码中)。
def approximate(dictionary, key):
assert dictionary and all(isinstance(k, int) for k in dictionary)
i = 0
while True:
if key + i in dictionary:
return dictionary[key + i]
if key - i in dictionary:
return dictionary[key - i]
i += 1
我以为我会包含这个,因为如果您正在查找的整数总是接近字典的键,这可能是一个很好的解决方案。
答案 2 :(得分:0)
最好你要做的就是O(n)运行时。
def closestKey(dic, key):
diff = {k:abs(k - key) for k in dic}
return min(diff, key=diff.get)
答案 3 :(得分:0)
除了迭代整个字典,然后通过记录min_diff以及将密钥本身作为变量查看最接近哪个密钥,我没有看到任何其他方法。
或者,您可以尝试使用有序的dict来节省一些时间,但不管怎样,它都会以线性时间运行。
答案 4 :(得分:0)
In [1]: def lookforkey(mykey, dd):
...: """ returns mykey if present in dd
...: otherwise the nearest key
...: which could be either greater or less
...: than mykey
...: """
...: nearkey = next(iter(dd))
...: bestdist = abs(nearkey - mykey)
...: for ikey in dd:
...: dist = abs(mykey - ikey)
...: if bestdist > dist:
...: bestdist = dist
...: nearkey = ikey
...: if ikey == mykey:
...: return ikey
...: return nearkey
...:
In [2]: dd = {2: 'x', 6: 'y', 77: 'w', 100000: 'z'}
In [3]: lookforkey(-10, dd)
Out[3]: 2
In [4]: lookforkey(6, dd)
Out[4]: 6
In [5]: lookforkey(76, dd)
Out[5]: 77
In [6]: lookforkey(999, dd)
Out[7]: 77
In [8]: lookforkey(999999, dd)
Out[9]: 100000
即使它更长,这比仍然处理密钥两次的最小/最大解决方案更有效。在这里,如果有完全匹配,则无需继续查看