11

I'm currently using something like

>> import itertools
>> ABC = [a, b, c]
>> abc = itertools.cycle( ABC )
>> next( abc )
a
>> next( abc )
b    
>> next( abc )
c

I want my next call to be

>> previous( abc )
b

Is there a method in itertools that can accomplish this?

Chris
  • 135
  • 1
  • 2
  • 10
  • Possible duplicate of [Making a python iterator go backwards?](https://stackoverflow.com/questions/2777188/making-a-python-iterator-go-backwards) – hiro protagonist Jun 18 '17 at 05:38

4 Answers4

11

You can use deque from collections module and rotate method, for example:

from collections import deque

alist=['a','b','c']
d=deque(alist)

current = d[0] 
print(current) # 'a'

d.rotate(1) # rotate one step to the right
current = d[0] 
print(current) # 'c'

d.rotate(-1) # rotate one step to the left
current = d[0] 
print(current) # 'a' again
Lynx
  • 271
  • 4
  • 7
10

No, there isn't.

Because of the way Python's iteration protocol works, it would be impossible to implement previous without keeping the entire history of the generated values. Python doesn't do this, and given the memory requirements you probably wouldn't want it to.

rici
  • 234,347
  • 28
  • 237
  • 341
4

You can write your own class to emulate an iterable object with next and previous. This is the simplest implementation:

class cycle:
    def __init__(self, c):
        self._c = c
        self._index = -1

    def __next__(self):
        self._index += 1
        if self._index>=len(self._c):
            self._index = 0
        return self._c[self._index]

    def previous(self):
        self._index -= 1
        if self._index < 0:
            self._index = len(self._c)-1
        return self._c[self._index]

ABC = ['a', 'b', 'c']
abc = cycle(ABC)
print(next(abc))
print(next(abc))
print(next(abc))
print(abc.previous())
  • That doesn't work on arbitrary iterable objects (such as a range or any of the iterables produced by itertools). It only works on indexable objects. – rici Apr 17 '18 at 02:41
  • 1
    Of course it doesn't! But the example was indexable, so this code works on it. – Sadjad Anzabi Zadeh Apr 17 '18 at 02:53
2

Although deque is the way to go, here's another example:

Code

import itertools as it


class Cycle:
    """Wrap cycle."""
    def __init__(self, seq):
        self._container = it.cycle(seq)
        self._here = None
        self.prev = None

    def __iter__(self):
        return self._container

    def __next__(self):
        self.prev = self._here
        self._here = next(self._container)
        return self._here

Demo

c = Cycle("abc")
next(c)
# 'a'
next(c)
# 'b'
c.prev
# 'a'
pylang
  • 40,867
  • 14
  • 129
  • 121