Est-il possible de faire un itérateur de liste python pour revenir en arrière?
Fondamentalement, j'ai ceci
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 __== '__main__':
test = IterTest(['a', 1, 2,3,'c', 17])
test.all()
L'exécution de ce code a pour résultat la sortie:
a
1
2
3
Crap i skipped C
Je sais pourquoi cela me donne la sortie, mais y a-t-il un moyen de revenir en arrière dans la méthode str (), d'un pas?
EDIT
Ok, peut-être pour que cela soit plus clair. Je ne veux pas faire l'inverse complet, essentiellement ce que je veux savoir s'il existe un moyen facile de faire l'équivalent d'un bidirectionnel itérateur en python?
Non, en général, vous ne pouvez pas faire revenir un itérateur Python en arrière. Cependant, si vous ne voulez vous retirer qu'une seule fois, vous pouvez essayer quelque chose comme ceci:
def str(self, item):
print item
prev, current = None, self.__iter.next()
while isinstance(current, int):
print current
prev, current = current, self.__iter.next()
Vous pouvez alors accéder à l'élément précédent à tout moment dans prev
.
Si vous avez vraiment besoin d'un itérateur bidirectionnel, vous pouvez en implémenter un vous-même, mais il est susceptible d'introduire encore plus de temps système que la solution précédente
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
Est-ce que quelque chose me manque ou est-ce que vous ne pouvez pas utiliser la technique décrite dans la section Itérateur du didacticiel Python?
>>> 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
Je sais que cela ne fait pas reculer l’itérateur, mais je suis à peu près sûr qu’il n’ya aucun moyen de le faire en général. A la place, écrivez un itérateur qui parcourt une collection discrète dans l'ordre inverse.
Edit vous pouvez également utiliser la fonction reversed()
pour obtenir un itérateur inversé pour n’importe quelle collection, de sorte que vous n’ayez pas à écrire le vôtre:
>>> it = reversed(['a', 1, 2, 3, 'c', 17])
>>> type(it)
<type 'listreverseiterator'>
>>> for each in it:
... print each
...
17
c
3
2
1
a
Un itérateur est par définition un objet avec la méthode next()
- aucune mention de prev()
que ce soit. Ainsi, vous devez soit mettre vos résultats en mémoire cache pour pouvoir les consulter à nouveau, soit réimplémenter votre itérateur pour qu'il renvoie les résultats dans l'ordre que vous souhaitez qu'ils soient.
D'après votre question, vous semblez vouloir quelque chose comme ceci:
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
Vous pouvez envelopper votre itérateur dans une aide d'itérateur pour lui permettre de revenir en arrière. Il stockera les valeurs itérées dans une collection et les réutilisera lors du retour en arrière.
class MemoryIterator:
def __init__(self, iterator : Iterator):
self._iterator : Iterator = iterator
self._array = []
self._isComplete = False
self._pointer = 0
def __next__(self):
if self._isComplete or self._pointer < len(self._array):
if self._isComplete and self._pointer >= len(self._array):
raise StopIteration()
value = self._array[self._pointer]
self._pointer = self._pointer + 1
return value
try:
value = next(self._iterator)
self._pointer = self._pointer + 1
self._array.append(value)
return value
except(StopIteration):
self._isComplete = True
def prev(self):
if self._pointer - 2 < 0:
raise StopIteration()
self._pointer = self._pointer - 1
return self._array[self._pointer - 1]
L'utilisation peut être similaire à celle-ci:
my_iter = iter(my_iterable_source)
memory_iterator = MemoryIterator(my_iter)
try:
if forward:
print(next(memory_iterator))
else:
print(memory_iterator.prev()
except(StopIteration):
pass
je pense que cela vous aidera à résoudre votre problème
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))
ls = [' a', 5, ' d', 7, 'bc',9, ' c', 17, '43', 55, 'ab',22, 'ac']
direct = -1
l = ls[::direct]
for el in l:
print el
Où direct est -1
pour inverse ou 1
pour ordinaire.