2010-03-10 33 views

Répondre

10

Vous pouvez envelopper le générateur dans un générateur qui génère une séquence de paires dont le premier élément est un booléen vous indiquant si l'élément est le dernier-mais-un:

def ending(generator): 
    z2 = generator.next() 
    z1 = generator.next() 
    for x in generator: 
     yield (False, z2) 
     z2, z1 = z1, x 
    yield (True, z2) 
    yield (False, z1) 

Testons sur simple iterator:

>>> g = iter('abcd') 
>>> g 
<iterator object at 0x9925b0> 

Vous devriez obtenir:

>>> for is_last_but_one, char in ending(g): 
...  if is_last_but_one: 
...   print "The last but one is", char 
... 
The last but one is c 

voir ce qui est trop Happ forcement sous le capot:

>>> g = iter('abcd') 
>>> for x in ending(g): 
...  print x 
... 
(False, 'a') 
(False, 'b') 
(True, 'c') 
(False, 'd') 
+0

+1 solution intelligente. –

+0

Wow. Merci! Bien que je dois encore envelopper ma tête autour de ce qui se passe dans la «fin» :) Tant de rendements. – bodacydo

2

Si vous voulez voir les valeurs futures arbitraires d'un iterator sans les consommer, vous pouvez envelopper le iterator dans un iterator « peekable », qui peut tamponner les valeurs futures.

import collections 

class PeekIter(object): 

    def __init__(self, iterable): 
     self._iter = iter(iterable) 
     self._peekbuf = collections.deque() 

    def next(self): 
     if self._peekbuf: 
      return self._peekbuf.popleft() 
     else: 
      return self._iter.next() 

    def peek(self, future=0, default=None): 
     try: 
      while len(self._peekbuf) <= future: 
       self._peekbuf.append(self._iter.next()) 
      return self._peekbuf[future] 
     except StopIteration: 
      return default 

Ensuite, vous pouvez jeter un coup d'œil aux valeurs futures sans les consommer.

>>> p = PeekIter(range(3)) 
>>> p.peek() 
0 
>>> p.next() 
0 
>>> p.peek(0) 
1 
>>> p.peek(0) 
1 
>>> p.peek(1) 
2 
>>> p.peek(2) 
>>> sentinel = object() 
>>> sentinel 
<object object at 0x28470> 
>>> p.peek(1, sentinel) 
2 
>>> p.peek(2, sentinel) 
<object object at 0x28470> 
+0

C'est génial. Merci! – bodacydo

1

une solution axée sur les itertools

from itertools import tee, islice, repeat, chain, izip 


def gen_with_offset(gen, offset): 
    gen1, gen2 = tee(gen) 
    gen2 = (False for x in gen2) 
    gen2 = chain(islice(gen2, offset, None), [True], repeat(False)) 
    for g, sentinel in izip(gen1, gen2): 
     yield g, sentinel 


Usage: 
>>> gex = iter('abcedefg') 
>>> for p in gen_with_offset(gex, 4): 
...  print p 
... 
('a', False) 
('b', False) 
('c', False) 
('e', False) 
('d', True) 
('e', False) 
('f', False) 
('g', False) 
>>>