休息后重新启动for循环

时间:2018-08-13 12:31:41

标签: python iterator

我有一个迭代器,该迭代器由多个相同大小的列表组成。为了我的目的,我需要知道这些列表中至少一个的长度。但是与迭代器一样,不能以与普通数组相同的方式访问它们。所以我的想法是通过说出这样的长度:

for i in iter:
    list_len = len(i)
    break

这是可行的,但是,当以后使用此列表并想要再次对其进行循环时,它将跳过第一次迭代,并且基本上从上一个循环(上一个循环)的下一个迭代继续进行。

有什么办法可以解决这个问题?或者,pythonic的实现方式是什么? 我在想/正在阅读这样做:

from itertools import tee

iter_tmp, iter = tee(iter)
for i in iter_tmp:
    list_len = len(i)
    break

是的,这也行得通,因为我现在可以使用原始的iter供以后使用,但是我不得不做一个循环,导入itertools之类的东西只是为了弄清楚它的长度,这让我的眼睛很痛。迭代器中的列表。但是也许这只是解决问题的方法?

更新

只是想进一步解释我在做什么。

因为这样的迭代不是列表或数组,但就我而言,如果我遍历迭代器,我会得到类似的信息(如果迭代器中有四个“列表”):

>>> for i in iter_list:
        print(i)
[1, 2, 5, 3]
[3, 2, 5, 8]
[6, 8, 3, 7]
[1, 4, 6, 1]

现在,迭代器中的所有“列表”都具有相同的长度,但是由于列表本身是通过许多步骤计算的,因此在进入迭代器之前,我真的不知道该长度。如果我不使用迭代器,则会耗尽内存-这是一个专业的解决方案。但是,是的,它只是我需要在常量代码的其余部分中使用的列表之一的长度。

3 个答案:

答案 0 :(得分:2)

这就是迭代器的工作方式。但是除了T恤之外,您还有其他选择。

您可以提取第一个元素并在第二次迭代时重新使用它:

first_elem = next(my_iter)
list_len = len(first_elem)

for l in itertools.chain([first_elem], my_iter):
    pass

或者如果您要遍历迭代器更多次,则可以列出它(如果可行的话,可以放入内存中)。

my_list = list(my_iter)
first_len = len(my_list[0])

for l in my_list:
    pass

当然,正如Palivek所说的那样,从其他地方保存/获取有关列表长度的信息。

答案 1 :(得分:0)

通常,迭代器不可重复迭代,因此您可能仍然需要存储一些其他内容。

class peek_iterator(object):
    def __init__(self, source):
        self._source = iter(source)
        self._first = None
        self._sent = False

    def __iter__(self):
        return self

    def next(self):
        if self._first is None:
            self._first = self._source.next()
        if self._sent:
            return self._source.next()
        self._sent = True
        return self._first

    def get_isotropic(self, getter):
        if self._first is None:
            self._first = self._source.next()
        return getter(self._first)

lists = [[1, 2, 3], [4, 5, 6]]

i = peek_iterator(lists)

print i.get_isotropic(len) # 3

for j in i: print j        # [1, 2, 3]; [4, 5, 6]

答案 2 :(得分:0)

您可以做一些技巧,将原始迭代器包装在生成器中。这样,您可以获取第一个元素并使用生成器“重新屈服”它,而无需消耗整个迭代器。下面的head()函数返回第一个元素和一个在原始序列上进行迭代的生成器。

def head(seq):
    seq_iter = iter(seq)
    first = next(seq_iter)
    def gen():
        yield first
        yield from seq_iter
    return first, gen()

seq = range(100, 300, 50)
first, seq2 = head(seq)

print('first item: {}'.format(first))

for item in seq2:
    print(item)

输出:

first item: 100
100
100
150
200
250

从概念上讲,它等效于Moberg's answer,但是使用生成器而不是itertools.chain()来“重新组合”原始序列。