Reputation: 20928
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
Upvotes: 3
Views: 128
Reputation: 9858
Marginally simpler than the reference function:
def lag(iter):
previous_item = next(iter)
for item in iter:
yield previous_item
previous_item = item
Upvotes: 2
Reputation: 81916
def one_behind(iter):
q = collections.deque()
q.append(next(iter))
while True:
q.append(next(iter))
yield q.popleft()
>>> iterator = iter(range(4))
>>> list(one_behind(iterator))
[0, 1, 2]
Upvotes: 0
Reputation: 368954
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]
Upvotes: 4