【问题标题】:Rewinding iteration [duplicate]倒带迭代[重复]
【发布时间】:2012-06-21 21:50:53
【问题描述】:

我一直在以简单的方式遍历列表的内容以获取用户输入:

for n in [ 1, 2, 3, 4 ]:
 command = raw_input ( "%d >> " % (n) )
 ...

我想实现一个撤消功能,这意味着将迭代“倒回”回之前的值。这是一种天真的方法,它确实减少了 n 的值,但随后跳过了原始值,因为指向列表的内部指针没有改变:

for n in [ 1, 2, 3, 4 ]:
 if f(n):
  n -= 1
 ...

在文档中,我看到了一个 iterator.next(),但没有看到 iterator.last()。我想我可以切换到通过整数索引访问列表成员,并通过自己操作索引来手动滚动循环,这并不是那么危险,但有没有更好的方法?

【问题讨论】:

  • 您必须自己实现它(自己保存最后 5-10 项),不可能“倒带”迭代器。此外,它是 Making a python iterator go backwards? 的副本
  • 我认为你可以使用while循环来实现这个。
  • 他说他有一个“列表”,我认为实际上不会使用range(1, 5) 列表。

标签: python iteration


【解决方案1】:

在现有的 Python 中没有明显的方法可以做到这一点,但是创建自己的支持回溯的迭代器很容易。例如,后面是一个“可搜索”的迭代器。寻找 relative 0 重复相同的元素,或 relative -1 回到前一个元素。

注意,因为这种迭代方式不享受“保证前进的进步”,它可能更容易出现无限循环。

class SeekableIterator(object):
    """An iterator that supports seeking backwards or forwards."""

    def __init__(self, iterable):
        """Make a SeekableIterator over an iterable collection."""

        self.iterable = iterable
        self.index = None

    def __iter__(self):
        """Start the iteration."""

        self.index = 0
        return self

    def next(self):
        """Return the next item in the iterator."""

        try:
            value = self.iterable[self.index]
            self.index += 1
            return value
        except IndexError:
            raise StopIteration

    def seek(self, n, relative=False):
        """Adjust the loop counter, either relatively or to an absolute index.
        Note that seeking 0 replays the current item. Seeking -1 goes to
        the previous item. If the adjustment pushes the index outside the
        iterable's bounds, raise an index error."""

        if relative:
            self.index += n - 1
            # NB index already advanced one in next(), so subtracting one here
        else:
            self.index = n
        if self.index < 0 or self.index >= len(self.iterable):
            raise IndexError


if __name__ == '__main__':

    import random

    def prob(percent):
        """Return True with roughly the given probability, else False"""
        return random.random() <= (percent * 1.0 / 100.0)

    seeker = SeekableIterator([1, 2, 3, 4])
    for n in seeker:
        print "n:", n

        if prob(50):
            if prob(50):
                print "\tREDO - seeking 0"
                seeker.seek(0, relative=True)
            elif n > 1:
                print "\tUNDO - seeking -1"
                seeker.seek(-1, relative=True)

这是一个示例输出:

n: 1
n: 2
n: 3
n: 4
    REDO - seeking 0
n: 4
    REDO - seeking 0
n: 4
    UNDO - seeking -1
n: 3
n: 4

【讨论】:

  • 非常笼统,pythonic,你对前进的进展是绝对正确的。谢谢乔纳森。
  • 在这个实现中,如果 relative=True 没有被传入,搜索似乎不会做任何事情。
  • 很好,@MatthewG!
【解决方案2】:

使用While 循环:

lis = [1, 2, 3, 4]
i = 0
while i < len(lis):
    if some_condition:
        print(lis[i])
        i += 1
    elif some_other_condition:
        print(lis[i])
        i -= 1

【讨论】:

  • 非常感谢 ashwini,这看起来很合理(也很容易)。
【解决方案3】:

共识是不,没有办法让python迭代器回溯。此线程有更多信息:

Making a python iterator go backwards?

但是,您可能会碰巧将循环重组为稍微不同的格式。考虑以下类似 python 的伪代码:

unprocessed = [1,2,3,...]
processed = []

traverse(unprocessed, processed, processor_function):
    item = unprocessed.head()
    unprocessed = unprocessed.tail()
    processed.prepend(item)
    if processor_function != None:
        processor_function(item)

如有必要,您的主循环逻辑可以按任意顺序调用 traverse,切换已处理和未处理,以模拟向后迭代。你可以传递任何你想要的处理函数,包括传递None 来简单地跳过处理。处理完所有元素后,列表将如下所示:

unprocessed = []
processed = [...,3,2,1]

这有点像图灵机。 “读头”总是在第一个列表的第一个元素之上,读头“右边”的所有元素都在第一个列表中,索引随距离升序,读头“左边”的所有元素都在在第二个列表中,索引随距离递增。最靠近读取头的元素是靠近每个列表开头的元素。

【讨论】:

    猜你喜欢
    • 2015-03-11
    • 1970-01-01
    • 2011-02-16
    • 1970-01-01
    • 2023-03-23
    • 2011-01-17
    • 2011-11-13
    • 2015-01-01
    相关资源
    最近更新 更多