Need to add an element at the start of an iterator

2020-07-13 06:24发布

问题:

I have a program as follows:

a=reader.next()
if *some condition holds*:
    #Do some processing and continue the iteration
else:
    #Append the variable a back to the iterator
    #That is nullify the operation *a=reader.next()*

How do I add an element to the start of the iterator? (Or is there an easier way to do this?)

EDIT: OK let me put it this way. I need the next element in an iterator without removing it. How do I do this>?

回答1:

Python iterators, as such, have very limited functionality -- no "appending" or anything like that. You'll need to wrap the generic iterator in a wrapper adding that functionality. E.g.:

class Wrapper(object):
  def __init__(self, it):
    self.it = it
    self.pushedback = []
  def __iter__(self):
    return self
  def next(self):
    if self.pushedback:
      return self.pushedback.pop()
    else:
      return self.it.next()
  def pushback(self, val):
    self.pushedback.append(val)

This is Python 2.5 (should work in 2.6 too) -- slight variants advised for 2.6 and mandatory for 3.any (use next(self.it) instead of self.it.next() and define __next__ instead of next).

Edit: the OP now says what they need is "peek ahead without consuming". Wrapping is still the best option, but an alternative is:

import itertools
   ...
o, peek = itertools.tee(o)
if isneat(peek.next()): ...

this doesn't advance o (remember to advance it if and when you decide you DO want to;-).



回答2:

You're looking for itertools.chain:

import itertools

values = iter([1,2,3])  # the iterator
value = 0  # the value to prepend to the iterator

together = itertools.chain([value], values)  # there it is

list(together)
# -> [0, 1, 2, 3]


回答3:

By design (in general development concepts) iterators are intended to be read-only, and any attempt to change them would break.

Alternatively, you could read the iterator backwards, and add it to the end of hte element (which is actually the start :) )?



回答4:

This isn't too close what you asked for, but if you have control over the generator and you don't need to "peek" before the value is generated (and any side effects have occurred), you can use the generator.send method to tell the generator to repeat the last value it yielded:

>>> def a():
...     for x in (1,2,3):
...             rcvd = yield x
...             if rcvd is not None:
...                     yield x
... 
>>> gen = a()
>>> gen.send("just checking")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't send non-None value to a just-started generator
>>> gen.next()
1
>>> gen.send("just checking")
1
>>> gen.next()
2
>>> gen.next()
3
>>> gen.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration