我可以将迭代器标记为过早完成吗?

2024-04-25 19:45:16 发布

您现在位置:Python中文网/ 问答频道 /正文

有没有一种惯用的方法来提前完成迭代器,以便下一步的任何一个()都能引发StopIteration?)我能想到一些丑陋的方式,比如虐待itertools.takewhile公司或者丢弃值,直到用尽为止)。你知道吗

编辑:

我的算法以n个长度未知的迭代器作为输入。它使用izip\u longest()从n元组中的每个元组中读取一个项,直到所有元组都用尽。有时,我发现我想根据某个运行时标准提前停止其中一个迭代器的输入,并用izipèu longest()提供的默认值流替换它。我能想到的最不具侵入性的方法就是以某种方式“完成”它。你知道吗


Tags: 方法算法编辑标准longest方式公司元组
3条回答

^{} Recipes

def consume(iterator, n):
    "Advance the iterator n-steps ahead. If n is none, consume entirely."
    # Use functions that consume iterators at C speed.
    if n is None:
        # feed the entire iterator into a zero-length deque
        collections.deque(iterator, maxlen=0)
    else:
        # advance to the empty slice starting at position n
        next(islice(iterator, n, n), None)

在您的编辑中,您给出了您的用例:您想要一些行为类似于izip_longest的东西,但是允许您过早地“禁用”迭代器。这里有一个迭代器类,它允许这样做,以及“启用”以前禁用的迭代器。你知道吗

class TerminableZipper(object):

    def __init__(self, iterators, fill="n/a"):
        self.iterators = collections.OrderedDict((it, True) 
                                                 for it in iterators)
        self.fill = fill
        self.zipper = itertools.izip_longest(*iterators, fillvalue=fill)

    def disable(self, iterator):
        self.iterators[iterator] = False
        self._make_iterators()

    def enable(self, iterator):
        self.iterators[iterator] = True
        self._make_iterators()

    def _make_iterators(self):
        def effective(it):
            iterator, active = it
            return iterator if active else iter([])

        effective_iterators = map(effective, self.iterators.items())                
        self.zipper = itertools.izip_longest(*effective_iterators, 
                                             fillvalue=self.fill)

    def __iter__(self):
        return self

    def next(self):
        return next(self.zipper)

举个例子:

>>> it_a = itertools.repeat(0)
>>> it_b = iter(["a", "b", "c", "d", "e", "f"])
>>> it_c = iter(["q", "r", "x"])
>>> zipper = TerminableZipper([it_a, it_b, it_c])
>>> next(zipper)
(0, 'a', 'q')
>>> next(zipper)
(0, 'b', 'r')
>>> zipper.disable(it_a)
>>> next(zipper)
('n/a', 'c', 'x')
>>> zipper.enable(it_a)
>>> next(zipper)
(0, 'd', 'n/a')
class MyIter:
    def __init__(self,what):
       self.what = what
       self.done = False
       self.iter = iter(what)
    def __iter__(self):
       self.done = False
       self.iter = iter(self.what)
    def next(self):
       if self.done: raise StopIteration
       return next(self.iter)

x = MyIter(range(100))
print next(x)
x.done=True
next(x)

但总的来说这听起来是个坏主意

你真正应该做的是

for my_iterator in all_iterators:
    for element in my_iterator: #iterate over it 
       if check(element): #if whatever condition is true
           break #then we are done with this iterator on to the next

对于@jme注释中列出的示例,请使用以下内容

for i,my_iterator in enumerate(all_iterators):
    for j,element in enumerate(my_iterator): #iterate over it 
       if j > i: #if whatever condition is true
           break #then we are done with this iterator on to the next
       else:
           do_something(element)

相关问题 更多 >