列表较大时未从列表中删除的项目

时间:2015-08-07 13:54:06

标签: python list parsing csv

我正在解析一个非常大的CSV文件。我只对其中两行(带有标题Ccy1Ccy2的行)感兴趣。

到目前为止,我的方法是解析整个文件,以及"批准的#34;列表中没有的任何字段。字段从列表中删除。

我在一个只有3行的小样本文件上尝试了这个,它运行正常。 当我解析了真正的文件,其中有107行,而不仅仅是#34;批准的"字段。

为什么不删除列表中没有的所有值。

这是我目前的剧本:

import csv
data = csv.reader(open('real_sample.csv'))
fields = data.next()
ccy_fields = ['Ccy1', 'Ccy2']

print 'fields: ' + str(fields)
print 'fields to keep: ' + str(ccy_fields)

for item in fields:
    if str(item) not in ccy_fields:
         fields.remove(item)

print "fields: " + str(fields)

3 个答案:

答案 0 :(得分:2)

您正在通过从循环体中的同一列表中删除项目来修改正在迭代的列表。这就是你问题的原因。

我建议列表理解是一种更好的方法:

fields = [item for item in fields if item in ccy_fields]

此外,csv模块为每个字段返回string类型的数据,因此无需使用str()进行转换。

从正在迭代的列表中删除项目时,您通常会看到紧跟删除项目后面的项目将被跳过。当您仅使用3列进行测试时,如果ccy_fields中有2列而其他列不是,则可能会看到正确的结果。当扩展到100多个项目时,会有跳过的符合删除条件的字段。

要解决您的问题,需要确定要保留的列的索引,然后用于过滤掉其他列:

import csv
ccy_fields = ['Ccy1', 'Ccy2']

with open('real_sample.csv') as f:
    reader = csv.reader(f)
    headers = next(reader)
    indices = [i for i,field in enumerate(headers) if field in ccy_fields]
    data = [[row[i] for i in indices] for row in reader]

在此之后,data将包含仅包含所需列的所有行。

答案 1 :(得分:1)

您需要获取列表的副本并首先对其进行迭代,否则迭代将失败,结果可能会出现意外结果。

for item in fields:
    if str(item) not in ccy_fields:
        fields.remove(item)    
#replace by
fields = [item for item in fields if str(item) in ccy_fields]

相关问题:Remove items from a list while iterating in Python

答案 2 :(得分:0)

您可能想要在阅读文件时直接考虑所需的字段,而不是获取所有数据然后修剪它。例如:

import csv
data   = csv.reader(open('real_sample.csv'))
wanted = []

for line in data:  # loop over the data without reading all of it into memory
    if ('Ccy1' in line or'Ccy2' in line):
        wanted.append(line)  # just keep the data when it matches you criteria