2010-05-05 22 views
17

¿Hay alguna forma de hacer que un iterador de la lista python retroceda?Hacer que un iterador de python vaya hacia atrás?

Básicamente tengo este

class IterTest(object): 
    def __init__(self, data): 
     self.data = data 
     self.__iter = None 

    def all(self): 
     self.__iter = iter(self.data) 
     for each in self.__iter: 
      mtd = getattr(self, type(each).__name__) 
      mtd(each) 

    def str(self, item): 
     print item 

     next = self.__iter.next() 
     while isinstance(next, int): 
      print next 
      next = self.__iter.next() 

    def int(self, item): 
     print "Crap i skipped C" 

if __name__ == '__main__': 
    test = IterTest(['a', 1, 2,3,'c', 17]) 
    test.all() 

Al ejecutar este código da como resultado la salida:

a 
1 
2 
3 
Crap i skipped C 

sé por qué me da la salida, sin embargo, es que hay una manera que puede paso atrás en la Método str(), por un paso?

EDITAR

Está bien, quizá para hacer esto más claro. No quiero hacer un revés completo, básicamente lo que quiero saber si hay una manera fácil de hacer el equivalente de un iterador bidireccional en python?

+0

¿Qué pasa con solo usar 'reversed'? ¿Desea explícitamente retroceder, o simplemente querer retroceder los resultados? – jathanism

+1

Oh .... ¿quieres detener la iteración intermedia y la copia de seguridad? Probablemente tengas que guardar en la memoria caché la parte de la lista que recorriste y recorrerla usando 'reverseed()' –

+0

. Puedo hacer eso, sin embargo, eso termina en un código molesto, en C++ tenemos soporte de iteración bidireccional. – UberJumper

Respuesta

17

No, en general no se puede hacer que un iterador de Python vaya hacia atrás. Sin embargo, si sólo desea dar un paso atrás una vez, puede intentar algo como esto:

def str(self, item): 
    print item 

    prev, current = None, self.__iter.next() 
    while isinstance(current, int): 
     print current 
     prev, current = current, self.__iter.next() 

A continuación, puede acceder al elemento anterior en cualquier momento prev.

Si realmente necesita un iterador bidireccional, puede implementar uno mismo, pero es probable que introduzca aún más sobrecarga que la solución anterior:

class bidirectional_iterator(object): 
    def __init__(self, collection): 
     self.collection = collection 
     self.index = 0 

    def next(self): 
     try: 
      result = self.collection[self.index] 
      self.index += 1 
     except IndexError: 
      raise StopIteration 
     return result 

    def prev(self): 
     self.index -= 1 
     if self.index < 0: 
      raise StopIteration 
     return self.collection[self.index] 

    def __iter__(self): 
     return self 
+0

Sí, estoy tratando de evitar esto, ya que esto agregará un poco de sobrecarga molesta:/ – UberJumper

+0

Agregué un ejemplo 'bidirectional_iterator' más arriba porque he visto que ha actualizado su pregunta, pero es probable que esto introduzca incluso más sobrecarga que mi primera solución. –

+0

Tenga en cuenta que esta clase __not__ no produce un iterador adecuado. Puede invocar manualmente .next() y .prev() en sus instancias, pero no puede aprovechar las facilidades de los iteradores como pasarlo en un bucle 'for' o una lista de comprensión. Eso generaría un 'TypeError: iter() devuelto non-iterator de tipo 'bidirectional_iterator''. – etuardu

3

Un iterador es por definición un objeto con el método next() - - sin mención de prev() en absoluto. Por lo tanto, debe almacenar en caché los resultados para poder volver a visitarlos o volver a implementar su iterador para que devuelva resultados en la secuencia que desea que sean.

3

Me estoy perdiendo algo o no podían usar el technique described in the Iterator section in the Python tutorial?

>>> class reverse_iterator: 
...  def __init__(self, collection): 
...   self.data = collection 
...   self.index = len(self.data) 
...  def __iter__(self): 
...   return self 
...  def next(self): 
...   if self.index == 0: 
...    raise StopIteration 
...   self.index = self.index - 1 
...   return self.data[self.index] 
...  
>>> for each in reverse_iterator(['a', 1, 2, 3, 'c', 17]): 
...  print each 
... 
17 
c 
3 
2 
1 
a 

Sé que esto no camina el iterador hacia atrás, pero estoy bastante seguro de que no hay manera de hacerlo en general. En su lugar, escriba un iterador que recorre una colección discreta en orden inverso.

Editar también puede utilizar la función reversed() para obtener un iterador invertido para cualquier colección de modo que usted no tiene que escribir su propia:

>>> it = reversed(['a', 1, 2, 3, 'c', 17]) 
>>> type(it) 
<type 'listreverseiterator'> 
>>> for each in it: 
... print each 
... 
17 
c 
3 
2 
1 
a 
+0

Una solución más simple y equivalente a esta sería utilizar el built-in 'invertido' que devuelve un iterador que camina sobre una conexión en orden inverso. –

+0

@ Tamás: Estaba escribiendo la edición tal como lo mencionaste. No pensé en eso hasta después de haber publicado la primera respuesta. –

+2

No quiero revertir todo el iterador. Estoy buscando el equivalente de un iterador bidireccional dentro de python. – UberJumper

1

Sobre la base de su pregunta, parece que usted querer algo como esto:

class buffered: 
    def __init__(self,it): 
     self.it = iter(it) 
     self.buf = [] 
    def __iter__(self): return self 
    def __next__(self): 
     if self.buf: 
      return self.buf.pop() 
     return next(self.it) 
    def push(self,item): self.buf.append(item) 

if __name__=="__main__": 
    b = buffered([0,1,2,3,4,5,6,7]) 
    print(next(b)) # 0 
    print(next(b)) # 1 
    b.push(42) 
    print(next(b)) # 42 
    print(next(b)) # 2 
0

creo Thi le ayudará a resolver su problema

class TestIterator(): 
     def __init__(self):` 
      self.data = ["MyData", "is", "here","done"] 
      self.index = -1 
      #self.index=len(self.data)-1 
    def __iter__(self): 
     return self 

    def next(self): 
     self.index += 1 
     if self.index >= len(self.data): 
      raise StopIteration 
     return self.data[self.index] 

    def __reversed__(self): 
     self.index = -1 
     if self.index >= len(self.data): 
      raise StopIteration 
     return self.data[self.index] 

r = TestIterator() 
itr=iter(r) 
print (next(itr)) 
print (reversed(itr))