6

Let's say I want to see the fifth item of an iterator, but I want to leave all the items on. What is the best way to do that? Is there a module? I could probably hack together a function that makes a new iterator, but I want to know if its already been done?

PyRulez
  • 10,513
  • 10
  • 42
  • 87

2 Answers2

7

I think what you want is itertools.tee, which essentially makes two iterators under the hood. Use one to peek, expending the items therein, while the contents "remain" in the other one.

In [10]: g = (i for i in range(5))

In [11]: a,b = itertools.tee(g)

In [12]: next(a)
Out[12]: 0

In [13]: next(a)
Out[13]: 1

In [14]: next(a)
Out[14]: 2

In [15]: next(b)
Out[15]: 0

Notice that next(b) returns 0 instead of 3, which is the behavior you are looking for

inspectorG4dget
  • 110,290
  • 27
  • 149
  • 241
5

The more_itertools third-party library has a more_itertools.spy tool that allows you to lookahead:

import more_itertools as mit

iterator = iter("abcdefg")
lookahead, iterable = mit.spy(iterator, 6) 
lookahead[5]
# 'f'

From the source, this tool essentially implements what @inspectorG4dget described. See also more_itertools.peekable.

pylang
  • 40,867
  • 14
  • 129
  • 121
  • Doesn't the current implementation (as of May 3rd, 2019) break on python 3.7 because of https://www.python.org/dev/peps/pep-0479/ ? – David V. May 03 '19 at 09:21
  • As of November 2019, more-itertools [works](https://github.com/erikrose/more-itertools/blob/3e3a9a7671cd047988580aa584c4b3f18cd635f7/tox.ini#L2) with Python 3.5, 3.6, 3.7, and 3.8. – Christian Long Nov 27 '19 at 16:00
  • Development on Python 2.7 was deprecated in 2019 (version 6.0.0). This particular recipe works on Python 2.7 as late as version 5.0.0. `pip install more_itertools < 6.0.0` – pylang Nov 27 '19 at 20:19