代码之家  ›  专栏  ›  技术社区  ›  Bastien Léonard

一个检查迭代器是否生成至少一个元素的行程序?

  •  76
  • Bastien Léonard  · 技术社区  · 14 年前

    目前我正在做:

    try:
        something = iterator.next()
        # ...
    except StopIteration:
        # ...
    

    但我想表达一个我可以放在一个简单的 if 语句。 有没有什么内置的东西可以让这个代码看起来不那么笨拙?

    any() 收益率 False 如果一个iterable为空,但如果它不是空的,它可能会迭代所有的项。 我只需要它来检查第一个项目。


    有人问我想做什么。 我编写了一个函数,它执行一个SQL查询并生成其结果。 有时,当我调用这个函数时,我只想知道查询是否返回了任何东西,并基于它做出决定。

    8 回复  |  直到 6 年前
        1
  •  114
  •   Jochen Ritzel    14 年前

    any 如果它是真的,就不会超出第一个元素。如果迭代器生成错误的ISH,您可以编写 any(True for _ in iterator) .

        2
  •  32
  •   Alex Martelli    14 年前

    在python 2.6+中,如果名称 sentinel 绑定到迭代器不可能生成的值,

    if next(iterator, sentinel) is sentinel:
        print('iterator was empty')
    

    如果您不知道迭代器可能会产生什么,那么使用

    sentinel = object()
    

    否则,您可以在sentinel角色中使用迭代器不可能生成的任何您“知道”(基于应用程序考虑)的值。

        3
  •  19
  •   Matthew Flaschen    14 年前

    这并不是很干净,但它显示了一种无损地将其打包到函数中的方法:

    def has_elements(iter):
      from itertools import tee
      iter, any_check = tee(iter)
      try:
        any_check.next()
        return True, iter
      except StopIteration:
        return False, iter
    
    has_el, iter = has_elements(iter)
    if has_el:
      # not empty
    

    这不是真正的蟒蛇,对于特定的情况,可能有更好(但不太一般)的解决方案,比如 next 违约。

    first = next(iter, None)
    if first:
      # Do something
    

    这不是一般性的,因为在许多iterables中没有一个元素是有效的。

        4
  •  5
  •   mykhal    14 年前

    你可以使用:

    if zip([None], iterator):
        # ...
    else:
        # ...
    

    但对于代码阅读器来说,这有点不太现实。

        5
  •  2
  •   Neil    7 年前

    如何:

    In [1]: i=iter([])
    
    In [2]: bool(next(i,False))
    Out[2]: False
    
    In [3]: i=iter([1])
    
    In [4]: bool(next(i,False))
    Out[4]: True
    
        6
  •  -1
  •   miku    14 年前

    __length_hint__ 估计 长度 list(it) -不过,这是私有方法:

    x = iter( (1, 2, 3) )
    help(x.__length_hint__)
          1 Help on built-in function __length_hint__:
          2 
          3 __length_hint__(...)
          4     Private method returning an estimate of len(list(it)).
    
        7
  •  -1
  •   doublep    14 年前

    这是一个overkill迭代器包装器,通常允许检查是否有下一个项(通过转换为布尔值)。当然效率很低。

    class LookaheadIterator ():
    
        def __init__(self, iterator):
            self.__iterator = iterator
            try:
                self.__next      = next (iterator)
                self.__have_next = True
            except StopIteration:
                self.__have_next = False
    
        def __iter__(self):
            return self
    
        def next (self):
            if self.__have_next:
                result = self.__next
                try:
                    self.__next      = next (self.__iterator)
                    self.__have_next = True
                except StopIteration:
                    self.__have_next = False
    
                return result
    
            else:
                raise StopIteration
    
        def __nonzero__(self):
            return self.__have_next
    
    x = LookaheadIterator (iter ([]))
    print bool (x)
    print list (x)
    
    x = LookaheadIterator (iter ([1, 2, 3]))
    print bool (x)
    print list (x)
    

    输出:

    False
    []
    True
    [1, 2, 3]
    
        8
  •  -1
  •   Jens Kirk Roybal    10 年前

    有点晚了,但是…您可以将迭代器转换为列表,然后使用该列表:

    # Create a list of objects but runs out the iterator.
    l = [_ for _ in iterator]
    
    # If the list is not empty then the iterator had elements; else it was empty.
    if l :
        pass # Use the elements of the list (i.e. from the iterator)
    else :
        pass # Iterator was empty, thus list is empty.