[英]Finding the closest pair of keys if lookup fails in a Python dictionary
假設我有一個Python字典,其中鍵實際上是整數。 我可以創建一個這樣的:
>>> d = dict([(1, 0), (7, 10), (28, 20)])
>>> d
{1: 0, 7: 10, 28: 20}
現在,我想查看如果找到密鑰,返回其索引。 這部分非常簡單,如下:
>>> key = 7
>>> d[key]
10
如果找不到密鑰,那么我想返回密鑰的邊界。 例如:
>>> key = 6
>>> d[key]
Bound(1, 7)
由於6不存在作為鍵,我將返回它所在的2個鍵。 沒有基本上迭代整個字典,這樣的事情可以嗎? 如果沒有,那么這個問題確實不需要回答。 如果這確實可行,請盡可能包括一些性能影響。 謝謝。
這是一個使用函數來訪問普通字典的解決方案(我使用OrderedDict
因為我現在有一個舊版本的Python,如果你有Python 3.6或更多,你可以使用普通dict
,因為它們是有序的。)
我們按鍵對dict進行排序,這讓我們可以使用bisect快速找到周圍的鍵。
import bisect
from collections import OrderedDict
d = OrderedDict(sorted([(1, 0), (7, 10), (28, 20)])) # Could be a simple dict with Python 3.6+
class Bound:
def __init__(self, a, b):
self.a = a
self.b = b
def __repr__(self):
return 'Bound({}, {})'.format(self.a, self.b)
def closest(key, d):
try:
return d[key]
except KeyError:
keys = list(d.keys())
ins_point = bisect.bisect(keys, key)
return Bound(keys[ins_point-1] if ins_point >= 1 else None,
keys[ins_point] if ins_point < len(keys) else None)
closest(7, d)
# 10
closest(8, d)
# Bound(7, 28)
closest(30, d)
# Bound(28, None)
closest(-1, d)
# Bound(None, 1)
你也可以__missing__
dict
,更新__missing__
方法(Python> = 3.6的代碼,假設dict
是有序的:
import bisect
class Bound:
def __init__(self, a, b):
self.a = a
self.b = b
def __repr__(self):
return 'Bound({}, {})'.format(self.a, self.b)
class BoundDict(dict):
def __missing__(self, key):
keys = list(self.keys())
ins_point = bisect.bisect(keys, key)
return Bound(keys[ins_point-1] if ins_point >= 1 else None,
keys[ins_point] if ins_point < len(keys) else None)
d = BoundDict(sorted([(1, 0), (7, 10), (28, 20)]))
print(d[7])
# 10
print(d[8])
# Bound(7, 28)
print(d[30])
# Bound(28, None)
print(d[-1])
# Bound(None, 1)
自定義dict類的解決方案:
import bisect
import collections
class Bound:
def __init__(self, left, right):
self.left = left
self.right = right
def __repr__(self):
return 'Bound({}, {})'.format(self.left, self.right)
class MyDict(collections.defaultdict):
def __init__(self, *args, **kwargs):
super().__init__()
dict.__init__(self, *args, **kwargs)
self.lst = sorted(key for key in self)
def __setitem__(self, key, value):
if key not in self:
bisect.insort_left(self.lst, key)
super().__setitem__(key, value)
def __delitem__(self, key):
self.lst.remove(key)
super().__delitem__(key)
def __missing__(self, key):
right_index = bisect.bisect(self.lst, key)
left_index = right_index - 1
right = self.lst[right_index] if right_index != len(self.lst) else None
left = self.lst[left_index] if left_index != -1 else None
return Bound(left, right)
d = MyDict([(1, 0), (7, 10), (28, 20)])
print(d[-3]) # Bound(None, 1)
print(d[6]) # Bound(1, 7)
print(d[7]) # 10
print(d[33]) # Bound(28, None)
del d[7]
print(d[6]) # Bound(1, 28)
def bound(x, d):
if x in d:
return x
else:
for i in sorted(d):
if x > i:
l = i
for j in sorted(d, reverse=True):
if j > x:
h = j
return(l,h)
d = dict([(1, 0), (7, 10), (28, 20), (4,5), (2,5), (15,10)])
bound(17,d)
(15,28)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.