Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/306.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 使用迭代器协议访问已排序的字典_Python_Dictionary_Iterator - Fatal编程技术网

Python 使用迭代器协议访问已排序的字典

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

我有一个字典“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.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'