让python迭代器倒退?

时间:2010-05-05 22:23:07

标签: python list iterator

有没有让python列表迭代器倒退?

基本上我有这个

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()

运行此代码会产生输出:

a
1
2
3
Crap i skipped C

我知道为什么它会给我输出,但是有一种方法我可以在str()方法中向后退一步吗?

修改

好吧也许可以让这个更清楚。我不想做完全反向,基本上我想知道是否有一种简单的方法在python中做相当于双向迭代器?

12 个答案:

答案 0 :(得分:23)

不,通常你不能让Python迭代器倒退。但是,如果您只想退一步,可以尝试这样的事情:

def str(self, item):
    print item

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

然后,您可以随时在prev

中访问上一个元素

如果你真的需要一个双向迭代器,你可以自己实现一个,但它可能会比上面的解决方案引入更多的开销:

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

答案 1 :(得分:6)

我错过了什么或者你不能使用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

我知道这不会向后移动迭代器,但我很确定通常无法做到这一点。相反,编写一个迭代器,以相反的顺序遍历离散集合。

编辑您还可以使用reversed()函数为任何集合获取反向迭代器,这样您就不必自己编写:

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

答案 2 :(得分:3)

根据定义,迭代器是一个带有next()方法的对象 - 无论如何都不提及prev()。因此,您必须缓存结果,以便重新访问它们或重新实现迭代器,以便按照您希望的顺序返回结果。

答案 3 :(得分:2)

根据你的问题,听起来你想要这样的东西:

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

答案 4 :(得分:1)

您可以将迭代器包装在迭代器帮助器中以使其能够向后移动。它会将迭代值存储在集合中,并在向后时重用它们。

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]

用法与此类似:

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

答案 5 :(得分:0)

我认为这将帮助您解决问题

    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))

答案 6 :(得分:0)

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

-1代表反向,而1代表普通。

答案 7 :(得分:0)

Python,您可以使用列表和索引来模拟迭代器:

a = [1,2,3]

current = 1

def get_next(a):
  current = a[a.index(current)+1%len(a)]
  return current
def get_last(a):
  current = a[a.index(current)-1]
  return current # a[-1] >>> 3 (negative safe)

如果您的列表包含重复项,那么您将不得不分别跟踪索引:

a =[1,2,3]
index = 0

def get_next(a):
  index = index+1 % len(a)
  current = a[index]
  return current
def get_last(a):
  index = index-1 % len(a)
  current = a[index-1]
  return current # a[-1] >>> 3 (negative safe)

答案 8 :(得分:0)

您可以通过以下代码使迭代器向后移动。

function debug_to_console($cf7) {
    echo '<div display="none"><script type="text/javascript">console.log("console log message");</script></div>';
    //return $cf7;
}

add_action( 'wpcf7_before_send_mail', 'debug_to_console' );

用法:

class EnableBackwardIterator:
    def __init__(self, iterator):
        self.iterator = iterator
        self.history = [None, ]
        self.i = 0

    def next(self):
        self.i += 1
        if self.i < len(self.history):
            return self.history[self.i]
        else:
            elem = next(self.iterator)
            self.history.append(elem)
            return elem

    def prev(self):
        self.i -= 1
        if self.i == 0:
            raise StopIteration
        else:
            return self.history[self.i]

答案 9 :(得分:0)

以相反顺序访问列表元素的迭代器:

GIT_TRACE_REDACT=0

答案 10 :(得分:0)

我来这里是为了寻找一个双向迭代器。不确定这是否是 OP 正在寻找的内容,但这是制作双向迭代器的一种方法——通过给它一个属性来指示接下来要进入的方向:

class BidirectionalCounter:
    """An iterator that can count in two directions (up
    and down).
    """

    def __init__(self, start):
        self.forward = True
        # Code to initialize the sequence
        self.x = start

    def __iter__(self):
        return self

    def __next__(self):
        if self.forward:
            return self.next()
        else:
            return self.prev()
    
    def reverse(self):
        self.forward = not self.forward
        
    def next(self):
        """Compute and return next value in sequence.
        """
        # Code to go forward
        self.x += 1
        return self.x
    
    def prev(self):
        """Compute and return previous value in sequence.
        """
        # Code to go backward
        self.x -= 1
        return self.x

演示:

my_counter = BidirectionalCounter(10)
print(next(my_counter))
print(next(my_counter))
my_counter.reverse()
print(next(my_counter))
print(next(my_counter))

输出:

11
12
11
10

答案 11 :(得分:-1)

请参阅Morten Piibeleht所做的此功能。它为可迭代的每个元素生成一个(上一个,当前,下一个)元组。

https://gist.github.com/mortenpi/9604377