Пронумеруйте строки один раз, извлекая любую дату, проверьте, установлена ли дата в наборе, если поэтому увеличивает счетчик с помощью Counter Dict для подсчетов, на Counter.most_common конца вызова, чтобы получить 5 самых общие даты:
dates1 = {'21/5/2015', '4/4/2015', '15/6/2015', '30/1/2015', '19/3/2015', '25/2/2015', '25/5/2015', '8/2/2015', '6/6/2015', '15/3/2015', '15/1/2015', '30/5/2015'}
from collections import Counter
import re
def dates(data, dates1):
lines = data.split("\n")
dict_days = Counter()
r = re.compile("\d+/\d+/\d+")
for line in lines:
match = r.search(line)
if match:
dte = match.group()
if dte in dates1:
dict_days[dte] += 1
return dict_days.most_common(5)
Это делает один проход над списком строк, в отличие от одного прохода для все даты в датах1.
Для 100k строк с датой строки в конце строки с 200+ символов:
In [9]: from random import choice
In [10]: dates1 = {'21/5/2015', '4/4/2015', '15/6/2015', '30/1/2015', '19/3/2015', '25/2/2015', '25/5/2015', '8/2/2015', '6/6/2015', '15/3/2015', '15/1/2015', '30/5/2015'}
In [11]: dtes = list(dates1)
In [12]: s = "the same dates appear in a text ('data' from now on). It's a pretty long text. I want to loop over the text and get the number of times each date appear in the text, then i print the 5 dates with more occurances. "
In [13]: data = "\n".join([s+ choice(dtes) for _ in range(100000)])
In [14]: timeit dates(data,dates1)
1 loops, best of 3: 662 ms per loop
Если более чем одна дата может появиться в каждой строке можно использовать FindAll:
def dates(data, dates1):
lines = data.split("\n")
r = re.compile("\d+/\d+/\d+")
dict_days = Counter(dt for line in lines
for dt in r.findall(line) if dt in dates1)
return dict_days.most_common(5)
Если данные фактически не являются файлом, подобным объекту, и представляют собой одну строку, просто выполните поиск самой строки:
def dates(data, dates1):
r = re.compile("\d+/\d+/\d+")
dict_days = Counter((dt for dt in r.findall(data) if dt in dates1))
return dict_days.most_common(5)
компилирования даты на тестовых данных, как представляется, самый быстрый подход, разделив каждую подстроку довольно близко к осуществлению поиска:
def dates_split(data, dates1):
lines = data.split("\n")
dict_days = Counter(dt for line in lines
for dt in line.split() if dt in dates1)
return dict_days.most_common(5)
def dates_comp_date1(data, dates1):
lines = data.split("\n")
r = re.compile("|".join(dates1))
dict_days = Counter(dt for line in lines for dt in r.findall(line))
return dict_days.most_common(5)
Используя функции выше:
In [63]: timeit dates(data, dates1)
1 loops, best of 3: 640 ms per loop
In [64]: timeit dates_split(data, dates1)
1 loops, best of 3: 535 ms per loop
In [65]: timeit dates_comp_date1(data, dates1)
1 loops, best of 3: 368 ms per loop
Предупреждение: 'если день в строке:' является опасным, потому что если 'день == '1/1/2015'' будет в строке, которая равна '21/1/2015 «'. – DSM
Используйте регулярные выражения вместо 'if day in line' и окружайте маркеры буквой' \ b', если они будут встречаться как целые слова. – mpcabd
фантастический улов @DSM – taesu