[英]Value-sorted dict for Python?
我对Python的dict
实现很感兴趣,它为排序值提供了一个迭代接口。 即,带有“ sortedvalues()
”函数的dict
。
天真的人可以做sorted(dict.values())
但这不是我想要的。 每次插入或删除项目时,都必须运行完全排序,这是无效的。
请注意,我也没有询问关键字排序的字典(对于那个问题, 在Python和Python 2.6 TreeMap / SortedDictionary中的Key-ordered dict中有很好的答案? )。
一种解决方案是编写一个继承自dict
的类,但也维护一个按其值( sorted_keys
)排序的键列表,以及相应(排序)值列表( sorted_values
)。
然后,您可以定义一个使用bisect
模块的__setitem__()
方法,以便快速了解应在两个列表中插入新(键,值)对的位置k
。 然后,您可以在字典本身和您维护的两个列表中插入新密钥和新值,并使用sorted_values[k:k] = [new_value]
和sorted_keys[k:k] = [new_key]
; 遗憾的是,这种插入的时间复杂度是O(n)
(因此整个字典的O(n^2)
)。
有序元素插入的另一种方法是使用heapq
模块并在其中插入(value, key)
对。 这适用于O(log n)
而不是前一段的基于列表的方法。
然后,迭代字典可以通过迭代您维护的键列表( sorted_keys
)来完成。
这种方法可以节省您每次要对字典进行迭代(具有排序值)时对键进行排序所需的时间,通过基本上将这个时间成本转移(并且不幸地增加)来构造排序的键列表和值。
问题是您需要按键对其进行排序或散列以获得合理的插入和查找性能。 实现它的一种天真的方式是条目的值排序树结构,以及查找键的树位置的字典。 您需要深入更新树,因为这个查找字典需要保持正确。 基本上,就像你可以为可更新堆做的那样。
我认为有太多的选择可以从这样的结构中制作出一个合理的标准库选项,而它却很少需要。
更新 :可能适合您的技巧是使用双重结构:
像往常一样存储键值对的常规dict
任何类型的排序列表,例如使用bisect
然后,您必须在两者上实现常见操作:将新值插入到两个结构中。 棘手的部分是更新和删除操作。 您使用第一个结构查找旧值,从第二个结构中删除旧值,然后(更新时)像以前一样重新插入。
如果您还需要知道密钥,请在b列表中存储(值,密钥)对。
更新2 :尝试这个类:
import bisect
class dictvs(dict):
def __init__(self):
self._list = []
def __setitem__(self, key, value):
old = self.get(key)
if old is None:
bisect.insort(self._list, value)
dict.__setitem__(self, key, value)
else:
oldpos = bisect.bisect_left(self._list, old)
newpos = bisect.bisect_left(self._list, value)
if newpos > oldpos:
newpos -= 1
for i in xrange(oldpos, newpos):
self._list[i] = self._list[i + 1]
else:
for i in xrange(oldpos, newpos, -1):
self._list[i] = self._list[i - 1]
self._list[newpos] = value
dict.__setitem__(self, key, value)
def __delitem__(self, key):
old = self.get(key)
if old is not None:
oldpos = bisect.bisect(self._list, old)
del self._list[oldpos]
dict.__delitem__(self, key)
def values(self):
return list(self._list)
我想这不是一个完整的dict
。 我没有测试删除,只是一个小的更新集。 你应该对它进行更大的单元测试,并将values()
的返回values()
与sorted(dict.values(instance))
的返回values()
进行比较。 这只是为了说明如何使用bisect
更新排序列表
这是另一个更简单的想法:
dict
的类。 在评论中提到几乎排序的排序列表很快,所以这种方法应该非常快。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.