我对Python的dict
实现感兴趣,它为排序值提供迭代接口。即,dict
具有“sortedvalues()
”功能。
天真地可以做sorted(dict.values())
,但这不是我想要的。每次插入或删除项目时,都必须运行完全排序,这是无效的。
请注意,我也不会询问关键字排序的字典(对于这个问题,Key-ordered dict in Python和Python 2.6 TreeMap/SortedDictionary?中有很好的答案。)
答案 0 :(得分:3)
一种解决方案是编写一个继承自dict
的类,但也维护按其值(sorted_keys
)排序的键列表,以及相应(排序)值列表({{ 1}})。
然后,您可以定义使用sorted_values
模块的__setitem__()
方法,以便快速了解位置bisect
,其中新(键,值)对应插入两个名单。然后,您可以使用k
和sorted_values[k:k] = [new_value]
将新密钥和新值插入字典本身以及您维护的两个列表中;遗憾的是,此类插入的时间复杂度为sorted_keys[k:k] = [new_key]
(因此整个词典的O(n)
。)
有序元素插入的另一种方法是使用O(n^2)
模块并在其中插入heapq
对。这适用于(value, key)
,而不是前一段中基于列表的方法。
迭代字典然后可以通过遍历您维护的键列表(O(log n)
)来完成。
这种方法可以节省你每次想要迭代字典(带有排序值)时对键进行排序所需的时间,基本上是将这个时间成本转移(并且不幸地增加)到排序列表的构造键和值。
答案 1 :(得分:2)
问题是您需要通过 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()
的返回值与sorted(dict.values(instance))
的返回值进行比较。这只是为了说明如何使用bisect
答案 2 :(得分:2)
这是另一个更简单的想法:
dict
。在评论中提到几乎排序的排序列表很快,所以这种方法应该非常快。
答案 3 :(得分:1)
您可以使用skip dict。它是一个Python值字典,按值永久排序。
插入比常规字典略贵,但如果您经常需要按顺序迭代,或执行基于值的查询,例如:
,则非常值得花费。