如何在python中快速获得字符串列表与模式列表的匹配结果?

如何在python中快速获得字符串列表与模式列表的匹配结果?,python,python-3.x,regex,python-2.7,Python,Python 3.x,Regex,Python 2.7,现在我有一个模式列表: list1 = ['a[0-9]+', 'b[a-z]+', 'c[A-Z]+', ...] 我还有一个字符串列表: list2 = ['a1', 'babc', 'cABC', 'bbb', 'c1', ...] 我希望快速知道list2中的字符串与list1中的哪个模式匹配,并返回其索引(如果不匹配任何模式,则返回-1): 现在,我只需使用“for”即可实现这一点: output = [] for string in list2: matched = Fals

现在我有一个模式列表:

list1 = ['a[0-9]+', 'b[a-z]+', 'c[A-Z]+', ...]
我还有一个字符串列表:

list2 = ['a1', 'babc', 'cABC', 'bbb', 'c1', ...]
我希望快速知道list2中的字符串与list1中的哪个模式匹配,并返回其索引(如果不匹配任何模式,则返回-1):

现在,我只需使用“for”即可实现这一点:

output = []
for string in list2:
  matched = False
  for pattern in list1:
    if re.match(pattern, string):
      output.append(list1.index(pattern))
      matched = True
      break
  if not matched:
    output.append(-1)
此方法可以工作,但由于list1和list2较大,因此需要花费的时间太长。那么还有其他方法可以快速返回结果吗?

您可以使用
map()
来缩短嵌套循环的运行时间。
通过减少一个
if
并删除创建和附加到另一个列表,以及避免列表的索引方法,您将减少总体运行时间

import re

list1 = ['a[0-9]+', 'b[a-z]+', 'c[A-Z]+']
list2 = ['a1', 'babc', 'cABC', 'bbb', 'c1']

def check_if_exist(item):
    for i, regex in enumerate(list1):
        if re.match(regex, item):
            return i
    return -1

print(list(map(check_if_exist, list2)))
输出

[0, 1, 2, 1, -1]
在时间中检查这两个方法。它返回带有
map()
的函数在0.17607659999997中运行,原始代码在0.1822188中运行10000次。

这将在大型列表中产生显著的差异。

尝试迭代表达式列表,并在已排序的字符串列表上执行对分搜索:

import re
list2  = ['a[0-9]+', 'b[a-z]+', 'c[A-Z]+']
list1 = sorted(['a1', 'babc', 'cABC', 'bbb', 'c1'])
output = []

def bisect_match(l, p, start, end):
    if(end-start+1 <= 0):
        return -1
    else:
        half = start + (end - start) // 2
        if(re.match(p, l[half])):
            return half
        else:
            if(l[half] > p):
                return(bisect_match)(l, p, start, half-1)
            else:     
                return(bisect_match)(l, p, half+1, end)

for string in list2:
    output.append(bisect_match(list1, string, 0, len(list1)))

print(output)
重新导入
清单2=['a[0-9]+'、'b[a-z]+'、'c[a-z]+']
列表1=已排序(['a1'、'babc'、'cABC'、'bbb'、'c1'])
输出=[]
def对分匹配(左、右、开始、结束):
如果(结束-开始+1 p):
返回(对分比赛)(左,右,开始,上半场1)
其他:
返回(对分匹配)(左,右,半+1,结束)
对于列表2中的字符串:
append(对分_匹配(list1,string,0,len(list1)))
打印(输出)

+1您建议的重构很好——将逻辑移到函数中(为了清晰起见),特别是不要不必要地使用
index()
(这肯定会加快速度)。然而,“函数式编程比循环更快”的概念大多是误导性的指导,至少没有针对当前问题的具体基准(您当前的基准将所有更改的影响混合在一起,而不仅仅是使用
map
)。例如,我怀疑列表理解会比这里的
map()
更快,但如果不对其进行基准测试,我不会断言这一点。感谢您的注释,我将很快尝试改进解释。顺便说一句,为了更好的解释,请编辑答案。我担心这不起作用,因为模式和字符串排序不同。例如,当list1=['ab1'、[a-z]+']和string='abc'时,它返回-1,因为'a[a-z]+'<'ab1'而'abc'>'ab1'。很抱歉,我没有正确测试我的解决方案。切换列表对您有用吗,这样您就可以对字符串而不是表达式进行排序?(请参阅我的编辑)编辑只返回第一个匹配项,因此可能对您也不起作用-抱歉!
import re
list2  = ['a[0-9]+', 'b[a-z]+', 'c[A-Z]+']
list1 = sorted(['a1', 'babc', 'cABC', 'bbb', 'c1'])
output = []

def bisect_match(l, p, start, end):
    if(end-start+1 <= 0):
        return -1
    else:
        half = start + (end - start) // 2
        if(re.match(p, l[half])):
            return half
        else:
            if(l[half] > p):
                return(bisect_match)(l, p, start, half-1)
            else:     
                return(bisect_match)(l, p, half+1, end)

for string in list2:
    output.append(bisect_match(list1, string, 0, len(list1)))

print(output)