如何分割生成器对象或迭代器?

问题描述 投票:10回答:4

我想遍历迭代器的“切片”。我不确定是否可行,因为据我了解无法对迭代器进行切片。我想做的是:

def f():
    for i in range(100):
        yield(i)
x = f()

for i in x[95:]:
    print(i)

这当然会失败:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-37-15f166d16ed2> in <module>()
  4 x = f()
  5 
----> 6 for i in x[95:]:
  7     print(i)

TypeError: 'generator' object is not subscriptable

是否有Python方式循环遍历生成器的“切片”?

基本上,我实际上关心的生成器读取一个很大的文件,并逐行对其执行一些操作。我想测试文件的片段以确保一切正常,但是让它在整个文件上运行非常耗时。

编辑:如前所述,我需要在文件上进行此操作。我希望有一种方法可以通过生成器明确地指定它,例如:

import skbio

f = 'seqs.fna'
seqs = skbio.io.read(f, format='fasta')

seqs是一个生成器对象

for seq in itertools.islice(seqs, 30516420, 30516432):
    #do a bunch of stuff here
    pass

上面的代码满足了我的需要,但是由于生成器仍然循环遍历所有行,所以它仍然很慢。我希望只循环指定的切片

python for-loop generator slice
4个回答
15
投票

[通常是answer is itertools.islice,但您应该注意,itertools.islice实际上也不会,也不会跳过值。它只是抓取并丢弃islice值,然后再开始start -ing值。因此,当您需要跳过很多值和/或被跳过的值获取/计算成本很高时,通常最好避免使用yield。如果可以找到一种方法,首先不要生成这些值。在您的(显然是人为的)示例中,您只需调整islice对象的起始索引。

在尝试在文件对象上运行的特定情况下,拉出大量的行(尤其是从慢速介质读取)可能不是理想的选择。假设您不需要特定的行,可以使用一种技巧来避免实际读取文件的大块,同时仍在测试到文件的距离,这是将range推测为偏移量,读出到末尾线(将可能要寻找的部分线丢弃到中间),然后从该点关闭seek即可。例如:

islice

对于文件的特定情况,您可能还希望查看可以以类似方式使用的import itertools with open('myhugefile') as f: # Assuming roughly 80 characters per line, this seeks to somewhere roughly # around the 100,000th line without reading in the data preceding it f.seek(80 * 100000) next(f) # Throw away the partial line you probably landed in the middle of for line in itertools.islice(f, 100): # Process 100 lines # Do stuff with each line (如果您正在处理数据块而不是文本行,则可能非常有用,它可能会随机地以你去)。

更新:

从更新后的问题中,您需要查看您的API文档和/或数据格式,以弄清楚如何正确跳过。看起来像mmap。如果以相等的序列长度写出数据,我将查看mmap上的文档;对齐的数据可能是可加载的,而根本不处理前面的数据,例如,skbio offers some features for skipping using seq_num, but that's still going to read if not process most of the file

您无法使用常规的skbio切片生成器对象或迭代器。相反,您需要将seq_num用作他的Alignment中已经提到的@jonrsharpe。

by using Alignment.subalignment to create new Alignments that skip the rest of the data for you

还请注意,Alignment.subalignment返回一个迭代器并使用该迭代器或生成器上的数据。因此,如果您需要回去做某事或使用鲜为人知的Alignment创建生成器的copy

,则需要将数据转换为列表或创建新的生成器对象。
slice operations

islice是pythonic方式

itertools.islice

让我们先澄清一下。您要根据在表达式左侧指定的参数数量从生成器中提取第一个值的配偶。从这一刻开始,我们遇到了一个问题,因为在Python中,有两种方法可以解压缩某些内容。

让我们使用以下示例讨论这些替代方案。假设您有以下列表l = [1、2、3]

1)第一种选择是不使用“开始”表达式

itertools.islice

如果表达式左侧的参数数量(在这种情况下为3个参数)等于列表中元素的数量,则效果很好。但是,如果您尝试这样的操作

comment

这是因为列表包含的参数比表达式左侧指定的参数多

2)第二种选择是使用“开始”表达式;解决先前的错误

import itertools    

for i in itertools.islice(x, 95)
    print(i)

“ start”参数的作用类似于缓冲区列表。缓冲区可以具有三个可能的值:

islice

请注意,列表必须至少包含2个值(在上面的示例中)。如果不是,将引发错误

现在,跳到您的问题。如果您尝试这样的操作:

itertools.tee

仅当生成器仅包含三个值(生成器值的数量必须与左参数的数量相同)时,此选项才有效。 Elese,将会出现错误。

如果您尝试这样的事情:

itertools.tee
  • 如果生成器中的值数小于2;因为变量“ a”,“ b”必须具有值],所以将引发错误。
  • 如果生成器中的值为3;然后a =,b =(val_2>,c = []
  • 如果生成器中的数值的整数大于3;然后a =,b =(val_2>,c = [,...]在这种情况下,如果生成器是无限的;试图消耗生成器的程序将被阻止

    我为您建议的是以下解决方案

from itertools import tee


first, second = tee(f())

2
投票

您无法使用常规的skbio切片生成器对象或迭代器。相反,您需要将seq_num用作他的Alignment中已经提到的@jonrsharpe。


1
投票

islice是pythonic方式

itertools.islice

0
投票

让我们先澄清一下。您要根据在表达式左侧指定的参数数量从生成器中提取第一个值的配偶。从这一刻开始,我们遇到了一个问题,因为在Python中,有两种方法可以解压缩某些内容。

让我们使用以下示例讨论这些替代方案。假设您有以下列表l = [1、2、3]

© www.soinside.com 2019 - 2024. All rights reserved.