Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

One-liner to check whether an iterator yields at least one element?

any won't go beyond the first element if it's True. In case the iterator yields something false-ish you can write any(True for _ in iterator).


In Python 2.6+, if name sentinel is bound to a value which the iterator can't possibly yield,

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

If you have no idea of what the iterator might possibly yield, make your own sentinel (e.g. at the top of your module) with

sentinel = object()

Otherwise, you could use, in the sentinel role, any value which you "know" (based on application considerations) that the iterator can't possibly yield.


This isn't really cleaner, but it shows a way to package it in a function losslessly:

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

This isn't really pythonic, and for particular cases, there are probably better (but less general) solutions, like the next default.

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

This isn't general because None can be a valid element in many iterables.


The best way to do that is with a peekable from more_itertools.

from more_itertools import peekable
iterator = peekable(iterator)
if iterator:
    # Iterator is non-empty.
else:
    # Iterator is empty.

Just beware if you kept refs to the old iterator, that iterator will get advanced. You have to use the new peekable iterator from then on. Really, though, peekable expects to be the only bit of code modifying that old iterator, so you shouldn't be keeping refs to the old iterator lying around anyway.


you can use:

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

but it's a bit nonexplanatory for the code reader


What about:

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