性能-在文本文件中搜索字符串-Python

性能-在文本文件中搜索字符串-Python,python,performance,list,Python,Performance,List,我有一套日期: 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'} 相同的日期出现在文本中(“从现在起的数据”)。这是一篇相当长的文章。我想在文本上循环,得到每个日期在文本中出现的次数,然后打印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'}
相同的日期出现在文本中(“从现在起的数据”)。这是一篇相当长的文章。我想在文本上循环,得到每个日期在文本中出现的次数,然后打印5个出现次数更多的日期

我现在得到的是:

def dates(data, dates1):
    lines = data.split("\n")
    dict_days = {}
    for day in dates1:
        count = 0
        for line in lines:
            if day in line:
                count += 1
        dict_days[day] = count

    newA = heapq.nlargest(5, dict_days, key=dict_days.get)

    print(newA)
我将tex分成几行,创建一个dict,对于列表中的每一个日期,它在每一行中查找它,如果它找到它,则将计数加1

这很好,但是运行这个方法需要很长时间

所以我想问的是,是否有人知道一种更有效的方法来做同样的事情

任何帮助都将不胜感激

编辑


我将尝试每一个答案,并让您知道,提前感谢

在行上循环一次,提取任何日期,检查日期是否在集合中,如果是,则在结束呼叫计数器处使用dict增加计数。最常见的获取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)
这会对行列表进行一次传递,而不是对Date1中的每个日期进行一次传递

对于日期字符串位于200个以上字符的字符串末尾的100k行:

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
我想这会很快奏效。。。。那么,为什么不直接做:

dates = {'21/5/2015':0, '4/4/2015':0, '15/6/2015':0, '30/1/2015':0, '19/3/2015':0, '25/2/2015':0, '25/5/2015':0, '8/2/2015':0, '6/6/2015':0, '15/3/2015':0, '15/1/2015':0, '30/5/2015':0}

def processDates(data):
    lines = data.split("\n")
    for line in lines:
        if line in dates:
           dates[line] += 1

然后只需按值对日期进行排序使用正则表达式提取数据,并使用
集合。计数器
查找最常见的:

import re
import collections

def dates(data, dates1):
    dates1 = '|'.join(x for x in dates1)
    dates1 = re.findall(dates1, data)
    dates1 = collections.Counter(dates1)
    print dates1.most_common(5)

dates1 = {'21/5/2015', '4/4/2015', '15/6/2015'}
data = 'Today is 21/5/2015. Yesterday is 4/4/2015.\nMy birthday is 4/4/2015'

dates(data, dates1)

警告:
如果日期在行:
是危险的,因为如果
日期=='1/1/2015'
它将位于
'21/1/2015'
的一行中。如果日期在行使用正则表达式而不是
,并用
\b
环绕标记,如果它们将作为整个单词出现。奇妙的catch@DSMYes,完美的catch,我应该如何改进这一点@看起来很棒。让我试试这个,我会让你知道的,先生。我不习惯
re
,但是
r=r.search(line)
?除了第一行之外,这难道不会阻止所有的行被扫描吗?@MathiasEttinger,我们在行上循环,一次获取每一行,我们从每一行中提取日期子字符串(如果有)并使用它。如果每行可以有一个以上的日期子字符串,OP可以使用findall和loop over,我理解代码,我关心的是通过它的result@MathiasEttinger,您指的是使用
r
?那是一个我改为匹配的打字错误
import re
import collections

def dates(data, dates1):
    dates1 = '|'.join(x for x in dates1)
    dates1 = re.findall(dates1, data)
    dates1 = collections.Counter(dates1)
    print dates1.most_common(5)

dates1 = {'21/5/2015', '4/4/2015', '15/6/2015'}
data = 'Today is 21/5/2015. Yesterday is 4/4/2015.\nMy birthday is 4/4/2015'

dates(data, dates1)