如何让Python迭代器反向遍历?

37 投票
14 回答
79819 浏览
提问于 2025-04-15 22:24

有没有办法让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中实现一个双向迭代器?

14 个回答

3

迭代器的定义是一个有 next() 方法的对象——这里没有提到 prev() 方法。因此,你要么需要保存你的结果,以便可以重新访问它们,要么就得重新实现你的迭代器,让它按照你想要的顺序返回结果。

10

我是不是漏掉了什么,或者说你不能用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

我知道这样做并不能让迭代器反向遍历,但我很确定一般来说是没有办法做到这一点的。相反,你可以写一个迭代器,让它以相反的顺序遍历一个具体的集合。

补充 你还可以使用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
36

不,一般来说,你不能让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

撰写回答