使用索引列表访问项目列表

13

考虑一个由大型csv文件(80MB)返回的具有可能间断间隔的大量命名项列表(第一行)

name_line =  ['a',,'b',,'c' .... ,,'cb','cc']

我正在逐行读取剩下的数据,我只需要处理相应名称的数据。 数据可能是这样的

data_line =  ['10',,'.5',,'10289' .... ,,'16.7','0']

我尝试了两种方法。一种是从读取的每行中弹出空列。

blnk_cols = [1,3, ... ,97]
while data:
    ...
    for index in blnk_cols: data_line.pop(index)

另一个是从L1编译与名称相关联的项目。

good_cols = [0,2,4, ... ,98,99]   
while data:
    ...
    data_line = [data_line[index] for index in good_cols]

在我使用的数据中,好行的数量肯定比坏行多,虽然可能达到一半。

我使用了cProfile和pstats包来确定速度最慢的地方,结果表明pop是当前最慢的项目。我尝试使用列表推导式,但时间几乎翻倍了。

我想象中一种快速的方法是切片数组,只检索好的数据,但对于交替空白和好数据的文件来说,这将很复杂。

我真正需要的是能够执行以下操作:

data_line = data_line[good_cols]

有效地传递索引列表到另一个列表中以获取这些项目。目前我的程序对于一个10MB的文件运行约为2.3秒,并且弹出帐户大约需要0.3秒。

是否有更快的方法来访问列表中的特定位置?在C语言中,只需将指向正确索引的指针数组取消引用即可。

补充说明:在读取之前文件中的name_line。

a,b,c,d,e,f,g,,,,,h,i,j,k,,,,l,m,n,

读取并使用逗号分隔符切割后的name_line

['a','b','c','d','e','f','g','','','','','h','i','j','k','','','','l','m','n','\n']

我正在逐行处理每一行。为了清晰起见进行了编辑。 - Paul Seeb
你是否正在使用 split(",") 解析 CSV 文件?使用 csv 模块会更好,因为它可以为你处理大部分工作。 - S.Lott
我正在删除列,因为这可以提高可读性并简化代码。此外,我需要在没有额外列的情况下编写。如果我使用索引并仅将所需值加载到数组中,我想这可能会导致我寻找的速度提升。我使用split函数,因为每行都是逗号分隔的,而该函数似乎非常适合这项工作。使用csv模块是否会产生任何速度优势或返回比split函数更好的列表? - Paul Seeb
弹出列似乎比索引解决方案更快(至少使用生成器),因为创建生成器似乎需要相当长的时间。 - Paul Seeb
用相应的for循环替换了生成器,得到了我期望的好处(去除了弹出时间并略微提升),总共减少了约0.4秒。 - Paul Seeb
显示剩余6条评论
1个回答

12

尝试使用生成器表达式。

data_line = (data_line[i] for i in good_cols)

在这里还可以阅读有关生成器表达式与列表推导式的内容。

正如顶部答案所告诉您的:“基本上,如果您只是迭代一次,请使用生成器表达式。”

因此,您应该从中受益。


哪个更快取决于你用它做什么。生成器的优点在于它是惰性的,因此你不需要为只访问一次的项目分配大量内存。 - Marcin
@Marcin。是的,我澄清了我的回答。 - Johan Lundberg
重构了所有代码以适应生成器表达式。我只需处理每行数据一次(使用带有适当索引的生成器,而不是最初弹出空值)。由于我需要为每行数据重新创建生成器表达式,因此代码运行速度慢了约0.3秒。 - Paul Seeb
@PaulSeeb 我有点困惑。创建生成器表达式不应该花费任何时间。 - Johan Lundberg
这个文件有25000行。我需要为每一行创建一个新的生成器来处理该行中的所有数据,除非我可以为每一行“重置”生成器。我对此进行了一些研究,并发现这是不可能的。 - Paul Seeb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接