web-dev-qa-db-fra.com

Faire un itérateur de python revenir en arrière?

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?

24
UberJumper

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
23
Tamás

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
6
D.Shawley

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.

3
ktdrv

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
2
David X

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
1

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))
0
dilshad
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.

0
robert tuw