2013-05-21 2 views
1

Мне нужно прочитать файл и разбить его на строки, а также разделить эти строки пополам на символы табуляции, а также избавиться от всех речевых меток. На данный момент у меня есть рабочая функция. Однако он довольно медленный:Python: что такое быстрый способ чтения и разбиения файла?

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

Это разделяет файл на список списков. Это действительно может быть только один список, так как было бы довольно легко переделать его на пары позже, пока порядок был сохранен.

Должен быть более быстрый способ сделать это. Может ли кто-нибудь поставить меня на правильный путь?

Спасибо!

[edit] Файл, с которым я работаю, массивный, но я добавлю что-то подобное. (Есть ли способ, чтобы загрузить файлы на переполнение стека?)

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

должен вернуться:

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

Хотя мой код возвращает его в виде списка списков 2 строк, который также хорошо.

Извините, я должен был заметить, что оператор печати стоит за оператором return - поскольку я взял это из функции, я изменил ее, чтобы печатать, поэтому здесь было бы больше смысла.

+2

образец файла и результат помогут нам создать ответы (для тестирования) – HennyH

+0

Конечно, я добавлю один. –

+0

Если все, что вы хотите, это печатный результат, вы можете просто распечатать в цикле for вместо добавления в список. – Gurgeh

ответ

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]) 

EDIT: поэтому производит уплощенной лист

>>> 
['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] 

An d некоторое время, оказывается, 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) 
+0

Большое спасибо, спасибо! –

+1

'chain.from_iterable' и выражение генератора сохраняют вас пунктуацией -' lines = chain.from_iterable (l.replace ('"', '') ... для l в f)'. Также нет необходимости использовать raw string - это не имеет никакого значения для строки, которая не имеет '\'. – lvc

+2

из моих тестов это выглядит медленнее. –

1

Вы должны сначала выяснить, каково ваше настоящее узкое место. Просто прочитайте файл, не создавая список результатов. Просто распечатайте каждую строку, когда она разделена, но не на консоль (с медленным), а на новый файл. Я бы очень признался, что он уже работает быстрее. Так что, на мой взгляд (не могу протестировать без реального дня), ваша проблема не в чтении и расщеплении. Это то, что вы делаете потом. Попробуйте. Дальнейшая оптимизация зависит от вашего конкретного варианта использования.

Update:

Учитывая ваш пример данных, вы можете попробовать это:

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

Это генерируя генератор для ваших данных. print list(...) предназначен только для печати и соответствует вашему примеру. В приложении реального мира вы, вероятно, не создадите список. Вместо этого напишите данные туда, куда они должны идти или обрабатывать их дальше.

Update2:

Если вы хотите избавиться от кавычек, и Вы уверены, что каждая часть имеет кавычки, вы могли бы просто использовать x[1:-1]. Или вы можете использовать x.strip('"'), если хотите быть уверенным. Но не нужно использовать регулярное выражение.

2

Заменяя temp.append на temp.extend, вы получаете список одиночных слоев вместо списка.

+0

Я хотел опубликовать это как комментарий, но у меня нет привилегии. – chenaren

+0

Я дам вам эту привилегию –

+0

Спасибо, я отдам. –

1

Если вы знаете, что на каждой строке есть только один \t, вы можете использовать split("\t",1) или rsplit("\t",1), чтобы избежать сканирования всей строки для вкладок.

strip('"') после split является возможной альтернативой replace("\"","") до split. Попробуйте, если это будет быстрее.

Но вы определили, сколько времени требуется только для чтения файла, используя file.read()? Является ли время, потраченное на разделение, действительно значительным по сравнению с этим?

+0

Спасибо! Должен был прочитать документацию; Я даже не знал, что вы можете это сделать. –

+0

Это хороший момент, спасибо. Возможно, расщепление не является моей проблемой. –

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 
+4

'splitlines()' сначала создаст весь список в памяти, а не эффективно. –

+0

Вам нужно будет создать полный список в памяти, который требует времени и ... потребляет много памяти. Почему это должно быть быстрее? – Achim

+0

В настоящее время он добавляет его в список и распечатывает список. –

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))) 
+0

Если вы собираетесь использовать весь итератор, версия списка 're.findall' будет быстрее – jamylak

+0

@jamylak Да, это так, но сначала создаст весь список в памяти. –

+0

Да, но линии короткие, это просто представит много накладных расходов. – jamylak

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'] 
1

, как это, например, :

>>> import csv 
>>> reader = csv.reader(open('testfile'), delimiter='\t', quotechar='"') 
>>> list(reader) 
[['CARMILLA', '35'], ['JONATHAN R', 'AA2'], ['M', '3'], ['EMMA', '350'], ['OLD', 'AA']] 
+0

нужно сгладить. – HennyH

+0

@HennyH: Цитирование OP: «Хотя мой код возвращает его как список списков из 2 строк, что тоже прекрасно. " Так что нет, его не нужно сглаживать. –

Смежные вопросы