遍历python中的CSV文件以查找带有前导空格的标题

时间:2018-07-11 19:48:55

标签: python python-3.x csv

我正在处理一个大型csv文件,其中包含歌曲及其所有者属性。每个歌曲记录都是自上而下编写的,每个标题下方都有相关的作者和发行者名称。因此,一首给定的歌曲可能包含4至6行,具体取决于控制该歌曲的作者/发行商的数量(例如下面的标题行):

Title,RoleType,Name,Shares,Note
BOOGIE BREAK 2,ASCAP,Total Current ASCAP Share,100,
BOOGIE BREAK 2,W,MERCADO JOSEPH M,,
BOOGIE BREAK 2,P,CRAFTIN MUSIC,,
BOOGIE BREAK 2,P,NEXT DIMENSION MUSIC,,

我目前正试图遍历整个文件,以提取所有包含前导空格的歌曲标题(例如“歌曲标题”)。这是我当前正在使用的代码:

import csv
import re

with open('output/sws.txt', 'w') as sws:
    with open('data/ascap_catalog1.csv', 'r') as ac:
        ascap = csv.reader(ac, delimiter=',')
        ascap = list(ascap)
        for row in ascap:
            for strings in row:
                if re.search('\A\s+', strings):
                    row = str(row)
                    sws.write(row) 
                    sws.write('\n')
                else:
                    continue

由于我正在使用的此csv文件的大小(〜2GB),因此迭代并生成结果文件需要花费大量时间。但是,根据我得到的结果,似乎带有前导空格的歌曲标题都聚集在文件的开头。这些歌曲全部列出后,就会出现没有前导空格的普通歌曲。

是否有办法使此代码在时间上更有效?我尝试在每个for和if语句之后使用几个break,但是根据我使用的数量,它要么根本不影响语句,要么中断得太快,没有捕获任何行。

我还尝试将其包装在函数中并实现return,但是由于某种原因,该代码似乎只在第一行进行迭代(不包括标题行,我会跳过)。

非常感谢您的时间,

4 个答案:

答案 0 :(得分:0)

您可以使用词典查找每首歌曲并将其所有关联值分组:

from collections import defaultdict
import csv, re
d = defaultdict(list)
count = 0 #count needed to remove the header, without loading the full data into memory
with open('filename.csv') as f:
  for a, *b in csv.reader(f):
    if count:
      if re.findall('^\s', a):
        d[a].append(b)
    count += 1

答案 1 :(得分:0)

list(ascap)并不是在帮您忙。 reader对象是其内容的迭代器,但是直到需要ti时,它们才将其全部加载到内存中。只需直接迭代reader对象即可。

对于每一行,只需检查row[0][0].isspace()。这将检查第一个条目的第一个字符,这是确定某些东西是否以空格开头所需的全部内容。

with open('output/sws.txt', 'w', newline="") as sws:
    with open('data/ascap_catalog1.csv', 'r', newline="") as ac:
        ascap = csv.reader(ac, delimiter=',')
        for row in ascap:
            if row and row[0] and row[0][0].isspace():
                print(row, file=sws)

您还可以处理输出,例如将要保留的所有行都保存在列表中,然后再写入末尾。如果所有开头的空白名称排在首位,听起来您的输入可能已被排序。在这种情况下,您只需添加else: break即可跳过文件的其余部分。

答案 2 :(得分:0)

以下是您可以改进的一些内容:

  • 直接使用reader对象作为迭代器,而无需创建中间列表。这样可以节省您的计算时间和内存。

  • 仅检查一行(标题)中的第一个值,而不是全部。

  • 删除不必要的else子句。

结合所有这些并应用一些最佳实践,您可以做到:

import csv
import re

with open('data/ascap_catalog1.csv') as ac, open('output/sws.txt', 'w') as sws: 
    reader = csv.reader(ac)
    for row in reader:
        if re.search(r'\A\s+', row[0]):
            print(row, file=sws)
  

似乎带有前导空格的歌曲标题都聚集在   文件的开头。

在这种情况下,只要标题带有前导空格,您就可以使用itertools.takewhile来迭代文件:

import csv
import re
from itertools import takewhile

with open('data/ascap_catalog1.csv') as ac, open('output/sws.txt', 'w') as sws:
    reader = csv.reader(ac)
    next(reader)  # skip the header
    for row in takewhile(lambda x: re.search(r'\A\s+', x[0]), reader):
        print(row, file=sws)

答案 3 :(得分:0)

这个对我来说效果很好,似乎很简单。

import csv
import re

with open('C:\\results.csv', 'w') as sws:
    with open('C:\\ascap.csv', 'r') as ac:
        ascap = csv.reader(ac, delimiter=',')
        for row in ascap:
            if re.match('\s+', row[0]):
                sws.write(str(row)+ '\n')