我正在尝试读取大型csv文件的某些特定行,我不想将整个文件加载到内存中。特定行的索引在列表L = [2, 5, 15, 98, ...]
中给出,我的csv文件如下所示:
Col 1, Col 2, Col3
row11, row12, row13
row21, row22, row23
row31, row32, row33
...
使用提到的想法here我使用以下命令来读取行
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]
我立即收到以下错误:
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
问题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)
问题2。有关如何改进这种贯穿整个文件的基本方法的想法,直到我到达第i行然后打印它?
答案 0 :(得分:7)
文件没有&#34;行&#34;或&#34;行&#34;。你认为是什么&#34; line&#34;是&#34;在两个换行符字符之间找到了什么&#34;。因此,如果不读取前面的行,则无法读取第n行,因为您无法计算换行符。
回答1 :如果你考虑你的例子,但是L = [9],展开你的循环会给出:
i=9
row = (0, {'Col 2': 'row12', 'Col 3': 'row13', 'Col 1': 'row11'})
如您所见,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
因此,当你想要处理这些行时,你会这样做:
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)
* 编辑 *
当您阅读了所有想要的行时,可以进一步改进以停止阅读文件:
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
答案 1 :(得分:2)
for row in enumerate(r):
将拉出元组。然后,您尝试从2元素元组中选择第i个元素。
例如
>> for i in enumerate({"a":1, "b":2}): print i
(0, 'a')
(1, 'b')
此外,由于字典是哈希表,因此不一定保留您的初始订单。例如:
>>list({"a":1, "b":2, "c":3, "d":5})
['a', 'c', 'b', 'd']
答案 2 :(得分:2)
假设L
是包含所需行号的列表,您可以这样做:
with open("~/file.csv") as f:
r = csv.DictReader(f)
for i, line in enumerate(r):
if i in L: # or (i+2) in L: from your second example
print line
那样:
唯一需要注意的是,即使L = [3]
答案 3 :(得分:1)
总结一下好主意,我最终使用了这样的东西:L
可以相对快速地排序,而在我的情况下,它实际上已经排序了。因此,不是在L
中进行多次成员资格检查,而是对其进行排序,然后仅针对第一个条目检查每个索引。这是我的代码:
count=0
with open('~/file.csv') as f:
r = csv.DictReader(f)
for row in r:
count += 1
if L == []:
break
elif count == L[0]:
print (row)
L.pop(0)
请注意,只要我们完成L
一次,就会停止。