Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterator that excludes the last element

What is a pythonic way to implement an iterator that excludes the last element, without knowing it's length?

An example:

>>> list(one_behind(iter(range(10)))
... [0, 1, 2, 3, 4, 5, 6, 7, 8]

>>> iter_ = one_behind(iter((3, 2, 1)))
>>> next(iter_)
... 3
>>> next(iter_)
... 2
>>> next(iter_)
... StopIteration

A simple approach would be to use a loop and store the previous value, but I'd like something a bit shorter.

Reference implementation using a loop:

def one_behind(iter_):
    prev = None
    for i, x in enumerate(iter_):
        if i > 0:
            yield prev
        prev = x
like image 795
simonzack Avatar asked Jul 17 '26 11:07

simonzack


2 Answers

Using itertools.tee:

import itertools

def behind(it):
    # it = iter(it)  # to handle non-iterator iterable.
    i1, i2 = itertools.tee(it)
    next(i1)
    return (next(i2) for x in i1)

usage:

>>> list(behind(iter(range(3))))
[0, 1]
like image 73
falsetru Avatar answered Jul 20 '26 00:07

falsetru


Marginally simpler than the reference function:

def lag(iter):
    previous_item = next(iter)
    for item in iter:
        yield previous_item
        previous_item = item
like image 36
Stuart Avatar answered Jul 20 '26 01:07

Stuart