Kei*_*van 8 python csv large-files
我试图读取一个大型csv文件的一些特定行,我不想将整个文件加载到内存中.特定行的索引在列表中给出L = [2, 5, 15, 98, ...],我的csv文件如下所示:
Col 1, Col 2, Col3
row11, row12, row13
row21, row22, row23
row31, row32, row33
...
Run Code Online (Sandbox Code Playgroud)
with open('~/file.csv') as f:
r = csv.DictReader(f) # I need to read it as a dictionary for my purpose
for i in L:
for row in enumerate(r):
print row[i]
Run Code Online (Sandbox Code Playgroud)
我立即得到以下错误:
IndexError Traceback (most recent call last)
<ipython-input-25-78951a0d4937> in <module>()
6 for i in L:
7 for row in enumerate(r):
----> 8 print row[i]
IndexError: tuple index out of range
Run Code Online (Sandbox Code Playgroud)
问题1.似乎我在for这里使用循环显然是错误的.有想法该怎么解决这个吗?
另一方面,以下内容完成了工作,但速度太慢了:
def read_csv_line(line_number):
with open("~/file.csv") as f:
r = csv.DictReader(f)
for i, line in enumerate(r):
if i == (line_number - 2):
return line
return None
for i in L:
print read_csv_line(i)
Run Code Online (Sandbox Code Playgroud)
问题2.关于如何改进这种贯穿整个文件的基本方法的想法,直到我到达行然后打印它?
文件没有"行"或"行".您认为"线"是"两个换行符之间的内容".因此,如果不读取前面的行,则无法读取第n行,因为您无法计算换行符.
答案1:如果你考虑你的例子,但是L = [9],展开你的循环将给出:
i=9
row = (0, {'Col 2': 'row12', 'Col 3': 'row13', 'Col 1': 'row11'})
Run Code Online (Sandbox Code Playgroud)
如您所见,row是一个带有两个成员的元组,调用row[i]方法row[9],因此是IndexError.
答案2:这非常慢,因为您每次都要读取文件到行号.在你的例子中,你读了前2行,然后是前5行,然后是前15行,然后是前98行等.所以你已经读了前5行3次.您可以创建一个只返回所需行的生成器(注意,行号将为0索引):
def read_my_lines(csv_reader, lines_list):
for line_number, row in enumerate(csv_reader):
if line_number in lines_list:
yield line_number, row
Run Code Online (Sandbox Code Playgroud)
所以当你想要处理这些线时,你会这样做:
L = [2, 5, 15, 98, ...]
with open('~/file.csv') as f:
r = csv.DictReader(f)
for line_number, line in read_my_lines(r, L):
do_something_with_line(line)
Run Code Online (Sandbox Code Playgroud)
*编辑*
当您阅读了所需的所有行时,可以进一步改进以停止读取文件:
def read_my_lines(csv_reader, lines_list):
# make sure every line number shows up only once:
lines_set = set(lines_list)
for line_number, row in enumerate(csv_reader):
if line_number in lines_set:
yield line_number, row
lines_set.remove(line_number)
# Stop when the set is empty
if not lines_set:
raise StopIteration
Run Code Online (Sandbox Code Playgroud)