我想编写一个像字典一样的容器类(实际上是从字典派生的),这个结构的键是日期。
当使用密钥(即日期)从类中检索值时,如果日期不存在,则使用密钥之前的下一个可用日期来返回该值。
以下数据应该有助于进一步解释这个概念:
Date (key) Value
2001/01/01 123
2001/01/02 42
2001/01/03 100
2001/01/04 314
2001/01/07 312
2001/01/09 321
如果我尝试获取与密钥(日期)'2001/01/05'相关联的值,我应该获得存储在密钥2001/01/04下的值,因为该密钥发生在密钥'2001/01 /之前05'如果它存在于字典中就会存在。
为了做到这一点,我需要能够进行搜索(理想情况下是二进制,而不是天真地遍历字典中的每个键)。我在Python词典中搜索过bsearch词典键查找 - 但是没有找到任何有用的东西。
无论如何,我想写一个这样的类来封装这种行为。
这是我到目前为止(不多):
#
class NearestNeighborDict(dict):
#
"""
#
a dictionary which returns value of nearest neighbor
if specified key not found
#
"""
def __init__(self, items={}):
dict.__init__(self, items)
def get_item(self, key):
# returns the item stored with the key (if key exists)
# else it returns the item stored with the key
答案 0 :(得分:13)
您真的不想继承dict
,因为您无法真正重用其任何功能。相反,如果你想在创建之后也能够修改一个实例,那么继承抽象基类collections.Mapping
(或MutableMapping
),为此目的实现必不可少的特殊方法,你将获得其他{ {1}} - 类似ABC的“免费”方法。
您需要编码的方法是dict
(__getitem__
和__setitem__
,如果您想要可变性),__delitem__
,__len__
和{{1 }}
标准库的bisect模块为您提供了在排序列表之上有效实现这些功能所需的一切。例如......:
__iter__
你可能想要根据你想要返回的内容(或者你是否想要提高)来调整__contains__
,以避免各种角落情况,例如“import collections
import bisect
class MyDict(collections.Mapping):
def __init__(self, contents):
"contents must be a sequence of key/value pairs"
self._list = sorted(contents)
def __iter__(self):
return (k for (k, _) in self._list)
def __contains__(self, k):
i = bisect.bisect_left(self._list, (k, None))
return i < len(self._list) and self._list[i][0] == k
def __len__(self):
return len(self._list)
def __getitem__(self, k):
i = bisect.bisect_left(self._list, (k, None))
if i >= len(self._list): raise KeyError(k)
return self._list[i][1]
大于{{1}中的所有键}}”。
答案 1 :(得分:5)
sortedcontainers模块提供SortedDict类型,可以按排序顺序维护密钥,并支持对这些密钥进行二等分。该模块是纯Python和fast-as-C implementations,具有100%的测试覆盖率和数小时的压力。
例如:
from sortedcontainers import SortedDict
sd = SortedDict((date, value) for date, value in data)
# Bisect for the index of the desired key.
index = sd.bisect('2001/01/05')
# Lookup the real key at that index.
key = sd.iloc[index]
# Retrieve the value associated with that key.
value = sd[key]
由于SortedDict支持快速索引,因此您也可以轻松地向前或向后查看。 SortedDict也是一个MutableMapping,所以它应该在你的类型系统中很好地工作。
答案 2 :(得分:0)
我会扩展dict
,并覆盖__getitem__
和__setitem__
方法来存储已排序的键列表。
from bisect import bisect
class NearestNeighborDict(dict):
def __init__(self):
dict.__init__(self)
self._keylist = []
def __getitem__(self, x):
if x in self:
return dict.__getitem__(self, x)
index = bisect(self._keylist, x)
if index == len(self._keylist):
raise KeyError('No next date')
return dict.__getitem__(self, self._keylist[index])
def __setitem__(self, x, value):
if x not in self:
index = bisect(self._keylist, x)
self._keylist.insert(index, value)
dict.__setitem__(self, x, value)
你最好继承MutableMapping,但原则是一样的,上面的代码很容易适应。
答案 3 :(得分:0)
为什么不直接从dict.keys()维护一个排序列表并搜索?如果你是dict的子类,你甚至可以设法在添加值时在该列表上进行二进制插入。
答案 4 :(得分:0)
在bintrees.RBTree:https://pypi.python.org/pypi/bintrees/2.0.1
上使用floor_key方法