Python 在列表中查找重新编译匹配项的最快方法

Python 在列表中查找重新编译匹配项的最快方法,python,performance,list,python-2.5,Python,Performance,List,Python 2.5,我有一个包含120000行的文本文件,其中每行的格式完全相同: ean_码;plu;名称价格;国家 我尝试了各种操作,包括直接处理文件,如果文件只是用readlines()逐行加载到内存中并写入列表(在程序开始时),则会得到最佳结果 所以我有两行: matcher = re.compile('^(?:'+eanic.strip()+'(?:;|$)|[^;]*;'+eanic.strip()+'(?:;|$))').match line=[next(l.split(';') for l in l

我有一个包含120000行的文本文件,其中每行的格式完全相同: ean_码;plu;名称价格;国家

我尝试了各种操作,包括直接处理文件,如果文件只是用readlines()逐行加载到内存中并写入列表(在程序开始时),则会得到最佳结果

所以我有两行:

matcher = re.compile('^(?:'+eanic.strip()+'(?:;|$)|[^;]*;'+eanic.strip()+'(?:;|$))').match
line=[next(l.split(';') for l in list if matcher(l))]
do sth with line....
这些行试图完成的是,它们试图(尽可能快地)找到一个plu/ean,它是由用户在以下字段中输入的:ean\u代码或plu

我对第二行特别感兴趣,因为它会影响我在WinCE设备(Python2.5的PyCE端口)上的性能

我尝试了所有可能的解决方案来加快速度,但这是迭代特定列表以查找re.compile生成的匹配项的最快方法

除了列表理解中的之外,还有没有更快的方法来迭代大列表(在我的例子中是120000行)

我正在寻找任何类型的数据结构(在Python2.5之前都支持这种结构)的任何可能的方法,这将比上面两行更快地给出结果


只需提及,这是在手持设备(630MHz ARM)上执行的,该设备具有256MB RAM,并且除了USB之外没有任何连接。遗憾的是,数据库访问和存在不是一个选项。

首先我查找了一些可用于python 2.5的模块:

您可以使用来读取数据。可能更快

您可以通过网络存储数据。因此,您可以存储python对象(如dict、tuple、int等)。比较整数比在字符串中搜索更快

您遍历一个列表,但您说您的数据在一个文本文件中。不要在列表中加载整个文本文件。也许下面的内容足够快,并且没有必要使用我上面提到的模块

f = open('source.txt','r') # note: python 2.5, no with-statement yet
stripped_eanic = eanic.strip()
for line in f:
    if stripped_eanic in line: # the IDs have a maximum length, don't they? So maybe just search in line[:20]
        # run further tests, if you think it is necessary
        if further_tests:
            print line
            break
else:
    print "No match"
编辑


我考虑了我上面提到的:不要在列表中加载整个文件。我认为这是唯一正确的,如果您的搜索是一个一次性过程,并且您的脚本存在于此。但是,如果您想搜索多次,我建议使用
dict
(如beerbajay建议的)和
cPickle
-文件,而不是文本文件。

我制作了一个测试文件并测试了一些变体。通过在文件上迭代来搜索静态字符串的最快方法是在第行中使用
字符串

但是,如果您要使用加载的数据进行多次搜索(根据下面的测试编号,实际搜索次数超过30次),那么以
dicts
的形式为PLUs和EANs生成查找表并用于将来的搜索是值得的(计算)

loaded 120000 lines
question regex    0.114868402481
simpler regex     0.417045307159
other regex       0.386662817001
startswith        0.236350297928
string in         0.020356798172  <-- iteration winner
dict construction 0.611148500443
dict lookup       0.000002503395  <-- best if you are doing many lookups

只要您必须访问列表中的每一个元素,我会说不。只需使用string方法而不是正则表达式创建您自己的字符串解析器,它可能会更快。如果你展示一个你想要的输入和输出的例子,我相信有人可以帮助你优化。我不认为有一个简单的方法可以更快地完成这个操作。也许你需要重新思考一下你需要什么:有没有一种方法不使用正则表达式就拒绝某些行?你能用正则表达式一次匹配整个文本而不是每一行吗?在python中解析120000行总是有点慢,与解析操作的复杂性无关,因为有很多开销,我将在最初的文章中澄清。您甚至需要一个regexp吗?看起来您可以使用类似于[x代表x in[split(line,;”)代表f中的line.readlines()]的东西,如果x[0]是eanic]+1来测量对象。与定时函数相比,
f.readlines()
需要多长时间?您是否测试所有函数是否产生相同的结果?有些部分将包含其他部分值,例如,323中包含23,用于另一行中的PLU。因此:如果“+ean1+”;“在l或ean1+”;“==l[0:len(ean1)+1]”是我能找到的最接近于你(使用in)的解决方案,那么:在imena_artikala中,found=[l代表l]。更慢。@J.F.Sebastian不,它们产生的结果略有不同,但可能不足以产生任何差异。@sale1902您要对同一数据进行多次搜索吗?此外,考虑<<代码> <代码>字符串的速度大约是5倍;在分割结果字符串后,您可以得到一些误报并将其过滤掉。哦…天哪…在最后一行中查找一个值需要2毫秒,这意味着第120000行。和我之前得到的40毫秒相比…说真的…我再也不会使用这个列表了。Dict ftw!!!!得再进一步测试一下,但竖起100个大拇指!
import re
import timeit

def timefunc(function, times, *args):
    def wrap():
        function(*args)
    t = timeit.Timer(wrap)
    return t.timeit(times) / times

def question(lines):
    eanic = "D41RP9"
    matcher = re.compile('^(?:'+eanic.strip()+'(?:;|$)|[^;]*;'+eanic.strip()+'(?:;|$))').match
    line=[next(l.split(';') for l in lines if matcher(l))]
    return line

def splitstart(lines):
    eanic = "D41RP9"
    ret = []
    for l in lines:
        s = l.split(';')
        if s[0].startswith(eanic) or s[1].startswith(eanic):
            ret.append(l)
    return ret

def simpler(lines):
    eanic = "D41RP9"
    matcher = re.compile('(^|;)' + eanic)
    return [l for l in lines if matcher.search(l)]

def better(lines):
    eanic = "D41RP9"
    matcher = re.compile('^(?:' + eanic + '|[^;]*;' + eanic + ')')
    return [l for l in lines if matcher.match(l)]

def strin(lines):
    eanic = "D41RP9"
    return [l for l in lines if eanic in l]

def mkdicts(lines):
    ean = {}
    plu = {}
    for l in lines:
        s = l.split(';')
        ean[s[0]] = s
        plu[s[1]] = s
    return (ean, plu)

def searchdicts(ean, plu):
    eanic = "D41RP9"
    return (ean.get(eanic, None), plu.get(eanic, None))

with open('test.txt', 'r') as f:
    lines = f.readlines()

    print "loaded", len(lines), "lines"
    print "question regex\t", timefunc(question, 10, lines)
    print "simpler regex\t", timefunc(simpler, 10, lines)
    print "other regex\t", timefunc(simpler, 10, lines)
    print "startswith\t", timefunc(splitstart, 10, lines)
    print "string in\t", timefunc(strin, 10, lines)
    print "dict construction\t", timefunc(mkdicts, 10, lines)
    ean, plu = mkdicts(lines)
    print "dict lookup\t", timefunc(searchdicts, 10, ean, plu)