【问题标题】:Detect last iteration over dictionary.iteritems() in python检测python中dictionary.iteritems()的最后一次迭代
【发布时间】:2011-08-30 17:32:15
【问题描述】:

在使用iteritems() 遍历字典时,是否有一种简单的方法可以检测最后一次迭代?

【问题讨论】:

  • 请问为什么这很重要? Python 中的字典没有定义迭代顺序,那么最后一次迭代有什么特别之处呢?
  • 一般来说,'somestring'.join(d.iteritems())pprint 模块应该处理人们希望这样做的最常见问题
  • 为什么不改用 OrderedDict(记住插入顺序的字典)?
  • @Space_C0wb0y 我正在从 dict 构造 SQL 查询的 WHERE 部分,所以从某种意义上说,这也属于@ninjagecko 建议的类别。基于 cmets,我认为最有效的方法是通过改变 dict 的字符串表示来构造 SQL 语法。
  • 在这里找到了一个不错的解决方案.. stackoverflow.com/a/1630350/804616

标签: python dictionary


【解决方案1】:

没有。使用迭代器时,您对位置一无所知 - 实际上,迭代器可能是无限的。

除此之外,字典没有排序。所以如果你需要它,例如要在元素之间插入逗号,您应该获取项目,对它们进行排序,然后它们会遍历 (key, value) 元组的列表。当迭代这个列表时,您可以轻松计算迭代次数,从而知道您何时拥有最后一个元素。

【讨论】:

    【解决方案2】:

    有一个丑陋的方法来做到这一点:

    for i, (k, v) in enumerate(your_dict.iteritems()):
        if i == len(your_dict)-1:
            # do special stuff here
    

    但是你真的应该考虑是否需要这个。我几乎可以肯定还有另一种方法。

    【讨论】:

    • 假设字典不改变大小
    • @ninjagecko:如果是这样,那你就完蛋了。在迭代集合时调整集合的大小是一种应受惩罚的罪行,这是有原因的,它会产生高度混乱和毫无意义的结果,甚至比eval 更有用。
    【解决方案3】:
    it = spam_dict.iteritems()
    try:
        eggs1 = it.next()
        while True:
            eggs2 = it.next()
            do_something(eggs1)
            eggs1 = eggs2
    except StopIteration:
        do_final(eggs1)
    

    快速而且很脏。它解决了你的问题吗?

    【讨论】:

    • -1。这在功能上等同于更简单的 for 循环:for eggs in spam_dict.iteritems(): do_something(eggs),然后在 for 循环之后:do_final(eggs)
    • 由于更正而删除了我的 -1。但是,鉴于 Space_C0wb0y 的丑陋答案不那么丑陋且更易于理解,我不确定您为什么觉得有必要提供答案。
    • 顺便说一句,如果字典为空,对do_final(eggs1) 的调用会引发NameError
    • 好吧,我自己也不太确定。这只是一种不同的工作方式。也许不依赖长度会使其更稳定。
    【解决方案4】:

    正如其他人所说,字典没有明确的顺序,所以很难想象你为什么需要这个,但它就是

    last = None
    for current in your_dict.iteritems():
      if last is not None:
        # process last
      last = current
    
    # now last contains the last thing in dict.iteritems()
    if last is not None: # this could happen if the dict was empty
      # process the last item
    

    【讨论】:

    • 这可以工作,但你必须做MY_NONE = object()并使用MY_NONE而不是None,否则如果迭代器包含None,这将失败
    • iteritems 返回 kev/value 元组,因此它不能有 None。
    【解决方案5】:

    最有意义的方法是将循环包装在某个调用中,该调用包含一个挂钩,以便之后调用您的后迭代功能。

    这可以作为上下文管理器实现并通过“with”语句调用,或者对于旧版本的 Python,您可以使用旧的“try:”...“finally:”构造。它也可以包装在一个字典迭代是自调度的类中(“私有”方法),并且附录代码遵循公共方法中的内容。 (了解公共与私有之间的差异是意图和文档的问题,而不是 Python 强制执行的)。

    【讨论】:

      【解决方案6】:

      我最近遇到了这个问题,我认为这是最优雅的解决方案,因为它允许你写for i,value,isLast in lastEnumerate(...):

      def lastEnumerate(iterator):
          x = list(iterator)
          for i,value in enumerate(x):
              yield i,value,i==len(x)-1
      

      例如:

      for i,value,isLast in lastEnumerate(range(5)):
          print(value)
          if not isLast:
              print(',')
      

      【讨论】:

        【解决方案7】:

        这是this broader question 的一个特例。我的建议是创建一个 enumerate-like generator,它在最后一项上返回 -1:

        def annotate(gen):
            prev_i, prev_val = 0, gen.next()
            for i, val in enumerate(gen, start=1):
                yield prev_i, prev_val
                prev_i, prev_val = i, val
            yield '-1', prev_val
        

        如果您希望它处理序列以及生成器,请添加 gen = iter(gen)

        【讨论】:

          【解决方案8】:

          for 循环中的最后一项无论如何都会在 for 循环之后挂起:

          for current_item in my_dict:
              do_something(current_item)
          
          try:
              do_last(current_item)
          except NameError:
              print "my_dict was empty"
          

          即使在 for 循环之前使用名称“current_item”,尝试循环空字典似乎也会删除 current_item,因此出现 NameError

          【讨论】:

            【解决方案9】:

            您在上面的评论中声明您需要它来构造 SQL SELECT 语句的 WHERE 子句。也许这会有所帮助:

            def make_filter(colname, value):
                if isinstance(value, str):
                    if '%' in value:
                        return "%s LIKE '%s'" % (colname, value)
                    else:
                        return "%s = '%s'" % (colname, value)
                return "%s = %s" % (colname, value)
            
            filters = {'USER_ID':'123456', 'CHECK_NUM':23459, 'CHECK_STATUS':'C%'}
            whereclause = 'WHERE '+'\nAND '.join(make_filter(*x) for x in filters.iteritems())
            print whereclause
            

            打印出来的

            WHERE CHECK_NUM = 23459
            AND CHECK_STATUS LIKE 'C%'
            AND USER_ID = '123456'
            

            【讨论】:

              【解决方案10】:

              我知道这很晚,但我是这样解决这个问题的:

              dictItemCount = len(dict)
              dictPosition = 1
              for key,value in dict
                  if(dictPosition = dictItemCount):
                      print 'last item in dictionary'
                  dictPosition += 1
              

              【讨论】:

                【解决方案11】:

                另一种方法是枚举您的 dict 并将当前迭代与最后一个迭代进行比较。在我看来,它更容易查看和理解:

                for n, (key, value) in enumerate(yourDict.items()):
                    if yourDict[n] == yourDict[-1]:
                        print('Found the last iteration!:', n)
                

                或者你可以在迭代完成后做一些事情:

                for key, value in yourDict.items():
                    pass
                else:
                    print('Finished iterating over `yourDict`')
                

                【讨论】:

                • 您好!您能否详细说明您的解决方案为何以及如何解决您的答案中的问题?谢谢。
                猜你喜欢
                • 1970-01-01
                • 2018-02-06
                • 2017-01-16
                • 1970-01-01
                • 2011-07-11
                • 2019-06-04
                • 1970-01-01
                • 1970-01-01
                • 2013-03-18
                相关资源
                最近更新 更多