1

我需要读取一个文件并将其分成几行,并用制表符将这些行分成两半,以及去掉所有的语音标记。目前我有一个工作功能。但是,它相当慢:

temp = []
fp = open(fName, "r")
for line in fp:
    temp.append(line.replace("\"","").rstrip("\n").split("\t"))
print temp

这会将文件拆分为列表列表。它实际上可能只是一个列表,因为只要保留顺序,以后就可以很容易地将其重新划分成对。

必须有更快的方法来做到这一点。谁能让我走上正轨?

谢谢!

[编辑] 我正在使用的文件很大,但我会添加类似的内容。(有没有办法在堆栈溢出时上传文件?)

"CARMILLA"  "35"
"JONATHAN R"    "AA2"
"M" "3"
"EMMA"  "350"
"OLD"   "AA"

应该返回:

["CARMILLA", "35", "JONATHON R", "AA2", "M", "3", "EMMA", "350", "OLD", "AA"]

虽然我的代码将它作为 2 个字符串的列表返回,但这也很好。

抱歉,我可能应该注意到 print 语句代表 return 语句 - 因为我把它从一个函数中取出,所以我把它改成了 print,所以在这里更有意义。

4

8 回答 8

6

我认为列表理解会比调用.append每一行更快

from itertools import chain
with open('file.txt') as f:
    lines = chain.from_iterable([l.replace(r'"','').rstrip('\n').split('\t',1) for l in f])

编辑:所以它产生一个扁平列表

>>> 
['CARMILLA', '35', 'JONATHAN R', 'AA2', 'M', '3', 'EMMA', '350', 'OLD', 'AA']

非扁平化版本:

with open('file.txt') as f:
    lines = [l.replace(r'"','').rstrip('\n').split('\t',1) for l in f]

有些时候,结果证明 OP 是最快的?

import timeit
print("chain, list",timeit.timeit(r"""
with open('file.txt') as f:
    lines = chain.from_iterable([l.replace(r'"','').rstrip('\n').split('\t',1) for l in f])""",setup="from itertools import chain",number=1000))
print("flat       ",timeit.timeit(r"""
with open('file.txt') as f:
    lines = [l.replace(r'"','').rstrip('\n').split('\t',1) for l in f]""",setup="from itertools import chain",number=1000))
print("op's       ",timeit.timeit(r"""temp = []
fp = open('file.txt', "r")
for line in fp:
    temp.append(line.replace("\"","").rstrip("\n").split("\t"))
""",number=1000))
print("jamlyks    ",timeit.timeit(r"""
with open('file.txt', 'rb') as f:
    r = csv.reader(f, delimiter=' ', skipinitialspace=True)
    list(chain.from_iterable(r))""",setup="from itertools import chain; import csv",number=1000))
print("lennart    ",timeit.timeit(r"""
    list(csv.reader(open('file.txt'), delimiter='\t', quotechar='"'))""",setup="from itertools import chain; import csv",number=1000))

产量

C:\Users\Henry\Desktop>k.py
('chain, list', 0.04725674146159321)
('my flat    ', 0.04629905135295972)
("op's       ", 0.04391255644624917)
('jamlyks    ', 0.048360870934994915)
('lennart    ', 0.04569112379085424)
于 2013-05-21T09:04:01.103 回答
2

通过替换temp.appendtemp.extend,您将获得单层列表而不是列表列表。

于 2013-05-21T09:01:27.917 回答
1

你应该首先弄清楚你真正的瓶颈是什么。只需读取文件而不构建结果列表。只需在拆分时打印每一行,而不是打印到控制台(速度很慢),而是打印到一个新文件中。我敢打赌它已经快得多了。所以在我看来(没有真正的一天就无法测试)你的问题不在于阅读和拆分部分。这就是你之后要做的事情。试试看。如何进一步优化取决于您的确切用例。

更新:

鉴于您的示例数据,您可以试试这个:

import itertools
print list(itertools.chain(
    *( line.strip().split('\t') for line in file('sample.txt') )
))

它正在为您的数据生成生成器。这print list(...)仅用于打印并与您的示例保持一致。在现实世界的应用程序中,您可能不会创建列表。而是将数据写入它应该去的地方或进一步处理它。

更新2:

如果你想去掉引号并且你确定每个部分都有引号,你可以使用x[1:-1]. 或者你可以使用x.strip('"'),如果你想确定的话。但不需要使用正则表达式。

于 2013-05-21T09:00:58.913 回答
1

\t如果您知道每一行只有一个,则可以使用split("\t",1)rsplit("\t",1)避免扫描整行以查找制表符。

strip('"')aftersplitreplace("\"","")before的可能替代方案split。如果它更快,请尝试。

但是您是否计算过仅使用 读取文件需要多长时间file.read()?与此相比,分裂所花费的时间真的很重要吗?

于 2013-05-21T09:02:19.190 回答
1
Benchmarks on a 2mb file:

__author__ = 'robert'

from timeit import timeit

os_cached = open("data.csv").read()


def test_one():
    result = [line.split("\t") for line in open("data.csv").read().splitlines()]

def test_two():
    for line in open("data.csv"):
        line.split("\t")
        yield line

def test_three():
    for line in open("data.csv").read().splitlines():
        line.split("\t")
        yield line

  def test_four():
    from itertools import chain
    with open('data.csv') as f:
        lines = chain.from_iterable([l.replace(r'"','').rstrip('\n').split('\t',1) for l in f])
        return lines

print timeit("test_one()", setup="from __main__ import test_one", number=195)
print timeit("for line in test_two(): pass", setup="from __main__ import test_two", number=195)
print timeit("for line in test_three(): pass", setup="from __main__ import test_three", number=195)
print timeit("for line in test_four(): pass", setup="from __main__ import test_four", number=195)



7.34187420441
6.22663840184
6.60748983698
10.6207058679
于 2013-05-21T09:05:16.430 回答
1

像这样,例如:

>>> import csv
>>> reader = csv.reader(open('testfile'), delimiter='\t', quotechar='"')
>>> list(reader)
[['CARMILLA', '35'], ['JONATHAN R', 'AA2'], ['M', '3'], ['EMMA', '350'], ['OLD', 'AA']]
于 2013-05-21T09:34:31.663 回答
0

使用regex和列表理解:

import re
with open("abc") as f:
    lis = [x.group(1) for line in f for x in \
                             re.finditer(r'"([a-zA-Z0-9\s]+)"', line) ]
    print lis

输出:

['CARMILLA', '35', 'JONATHAN R', 'AA2', 'M', '3', 'EMMA', '350', 'OLD', 'AA']

如果制表符分隔值的数量不大,则使用re.findall()

lis =  [y for line in f for y in re.findall(r'"([a-zA-Z0-9\s]+)"', line)]

或使用itertools.chain

lis =  list(chain(*(re.findall(r'"([a-zA-Z0-9\s]+)"', line) for line in f)))
于 2013-05-21T09:15:34.717 回答
0
from itertools import chain
import csv

with open('data.txt', 'rb') as f:
    r = csv.reader(f, delimiter=' ', skipinitialspace=True)
    print list(chain.from_iterable(r))

['CARMILLA', '35', 'JONATHAN R', 'AA2', 'M', '3', 'EMMA', '350', 'OLD', 'AA']
于 2013-05-21T09:26:02.787 回答