Python 使用迭代器协议访问已排序的字典
我有一个字典“vcomments”,其中键是非顺序整数。当循环通过键时,我需要按排序或反向排序的顺序执行。目前我使用Python 使用迭代器协议访问已排序的字典,python,dictionary,iterator,Python,Dictionary,Iterator,我有一个字典“vcomments”,其中键是非顺序整数。当循环通过键时,我需要按排序或反向排序的顺序执行。目前我使用 for key_pt in sorted(self.view.vcomments.iterkeys()): 但我还需要找到那些超出某个数字或在某个数字之前的键(或下一个键): if direction == 'down': sorted_pts = (key_pt for key_pt in sorted(self.view.vcomments.iter
for key_pt in sorted(self.view.vcomments.iterkeys()):
但我还需要找到那些超出某个数字或在某个数字之前的键(或下一个键):
if direction == 'down':
sorted_pts = (key_pt for key_pt in sorted(self.view.vcomments.iterkeys()) if key_pt > curr_pt)
else:
sorted_pts = (key_pt for key_pt in reversed(sorted(self.view.vcomments.iterkeys())) if key_pt < curr_pt)
try:
next_pt = sorted_pts.next()
except StopIteration:
if direction==“down”:
sorted_pts=(如果key_pt>curr_pt,则在sorted(self.view.vcomments.iterkeys())中的key_pt的key_pt)
其他:
sorted_pts=(如果key_pt
补充:我仍然需要能够通过其键检索单个特定词典项。在这种情况下,我倾向于以两种不同的方式存储部分数据 如果您保留dict,但添加了一个由int索引的列表,该列表将显示dict的键(r值?),该怎么办?这将为您提供可能需要的随机访问(我假设您拥有dict是有原因的),以及您似乎需要添加的向后和向前行为 如果您这样做,您可能会将其全部封装在一个类中,这样您就不会在代码中散布双重更新
可能可以采用treap或红黑树实现,并对其进行修改,以允许您指定一个键,并在下一个或上一个键处返回键、值对。如果您经常插入或删除值,其中一个可能会更好。首先,您应该注意,您需要一个更好的数据结构。Python dict根本没有顺序,而
OrderedDict
只保留插入顺序(因此您需要在每次键更改时重新排序)。像blist.sortedlist
这样的排序字典,甚至像blist.sortedlist这样的排序列表,可能更适合您的需要
我是否可以创建一个迭代器类(使用迭代器协议)来存储字典并使我能够以正向或反向的顺序循环它们?我假设/猜测我可能需要首先指定一个属性值,该属性值将指示下一个循环是否应为正向/反向
这里不需要单独的迭代器类。您可以通过内置函数获得自由前向迭代和后向迭代:
for key in mydict:
# do something
for key in reversed(mydict.keys()):
# do something
def first_beyond(pivot, seq):
next(dropwhile(lambda x: x <= pivot, seq))
first_beyond(4, mydict)
first_beyond(20, reversed(mydict.keys()))
我可以在迭代器类中包含一个生成器函数(嵌套),使我能够检索下一个键;也就是说,在提供的整数之后或之前
当然,itertools
有很多功能,可以让您执行以下操作:
from itertools import dropwhile, takewhile
# find next key beyond 4
next(dropwhile(lambda x: x <= 4, mydict))
# find last key before 20
next(dropwhile(lambda x: x >= 20, reversed(mydict.keys()))
编辑:如果您只是偶尔需要检查已排序的键,您可以将它们转换为已排序的列表并使用它们。这些习语与上面的相同:
keys = sorted(mydict)
# forward and backward iteration
for k in keys:
# ...
for k in reversed(keys):
# ...
# function that returns a forward or backward iterator based on an argument
def forward_or_backward(seq, forward=True):
for x in (iter if forward else reversed)(seq):
yield x
# random access inside a loop
for i, key in enumerate(keys):
# next element
key[i+1]
# the between and first_beyond functions above also work for lists
您的其他功能可以从这些部件粘在一起。请注意,创建一个特殊类是不明智的,因为我们可以用一种足够通用的方式来编写函数,使它们可以处理任何可编辑的对象,而不仅仅是您的键列表。看起来ordereddict可能会满足您的需要。文档是。我认为满足您需求的最佳数据结构是。我从来没有实现过一个——一直都想实现——但在我看来,它具备了您需要的所有功能
跳过列表按排序顺序存储其项。使基列表成为双链接列表将允许在O(n)中进行正向和反向迭代
跳过列表允许O(logn)插入、修改、删除和搜索。这并不像字典那么快,但在我看来,如果你需要按排序顺序存储项目,字典会给你带来麻烦——即使是OrderedDict
,除非你很少添加键
通过上面wikipedia文章中描述的一些修改,甚至可以在O(logn)中实现索引访问
Python中有一个实现——可能还有其他实现
然而,您的一些评论表明,您可能满足于只对字典的排序副本进行迭代,而您只是试图清理上面的代码。所以这里有一个方法。这很幼稚,但这是一个起点。这假设您对O(n)搜索时间和O(n log n)迭代时间完全满意,这两个时间都是次优的
>>> class SortIterDict(dict):
... def __iter__(self):
... return iter(sorted(super(SortIterDict, self).__iter__()))
... def __reversed__(self):
... return reversed(tuple(iter(self)))
... def get_next(self, n):
... return next((x for x in iter(self) if x > n), None)
... def get_prev(self, n):
... return next((x for x in reversed(self) if x < n), None)
...
>>> d = SortIterDict({'d':6, 'a':5, 'c':2})
>>> list(d)
['a', 'c', 'd']
>>> list(reversed(d))
['d', 'c', 'a']
>>> d.get_next('b')
'c'
>>> d.get_prev('b')
'a'
>>分类分类分类(dict):
... 定义(自我):
... 返回iter(已排序(super(SortIterDict,self)。\uuu iter(uuuu()))
... 定义反向(自):
... 反向返回(元组(iter(self)))
... def get_next(自我,n):
... 返回next(如果x>n,则iter(自身)中的x代表x),无)
... def get_prev(自身,n):
... 返回下一个((如果x>>d=SortIterDict({'d':6,'a':5,'c':2})
>>>名单(d)
['a','c','d']
>>>名单(颠倒(d))
['d','c','a']
>>>d.下一步(“b”)
“c”
>>>d.get_prev('b')
“a”
OK,因此您需要定期检索密钥。你要加钥匙吗
keys = sorted(mydict)
# forward and backward iteration
for k in keys:
# ...
for k in reversed(keys):
# ...
# function that returns a forward or backward iterator based on an argument
def forward_or_backward(seq, forward=True):
for x in (iter if forward else reversed)(seq):
yield x
# random access inside a loop
for i, key in enumerate(keys):
# next element
key[i+1]
# the between and first_beyond functions above also work for lists
>>> class SortIterDict(dict):
... def __iter__(self):
... return iter(sorted(super(SortIterDict, self).__iter__()))
... def __reversed__(self):
... return reversed(tuple(iter(self)))
... def get_next(self, n):
... return next((x for x in iter(self) if x > n), None)
... def get_prev(self, n):
... return next((x for x in reversed(self) if x < n), None)
...
>>> d = SortIterDict({'d':6, 'a':5, 'c':2})
>>> list(d)
['a', 'c', 'd']
>>> list(reversed(d))
['d', 'c', 'a']
>>> d.get_next('b')
'c'
>>> d.get_prev('b')
'a'