搜索元组列表以查找匹配子字符串的算法方法?

Algorithmic way to search a list of tuples for a matching substring?

我有一个元组列表,大约有 10 万个条目。每个元组由一个 id 和一个字符串组成,我的目标是列出元组的 id,其字符串包含给定子字符串列表中的一个子字符串。 我目前的解决方案是通过集合理解,ids可以重复。

tuples = [(id1, 'cheese trees'), (id2, 'freezy breeze'),...]
vals = ['cheese', 'flees']
ids = {i[0] for i in tuples if any(val in i[1] for val in vals)}

output: {id1}

有没有一种算法可以更快地做到这一点?我对精确的子字符串匹配以及近似的子字符串匹配都感兴趣。我在这里追求的主要是一种算法,它可以提供速度优势而不是理解。

免责声明 我是 trrex

的作者

对于 精确匹配 的情况,解决这个问题的一种方法是使用 Trie, as mentioned in the comments. trrex 是一个制作 Trie-Regex 的库(一个 Trie正则表达式格式),可以与 Python:

的正则表达式引擎结合使用
import random
import pandas as pd
import trrex as tx
import re

df = pd.read_csv('jeopardy-small.csv')
with open('words-sample') as infile:
    words = [line.strip() for line in infile]


tuples = [(random.randint(1, 250), sentence) for sentence in df['question']]


def fun_kislyuk(ws, ts):
    return {t[0] for t in ts if any(w in t[1] for w in ws)}


def fun_trrex(ws, ts):
    pattern = re.compile(tx.make(ws, left='', right=''))
    return {i for i, s in ts if pattern.search(s)}


if __name__ == "__main__":
    print(fun_trrex(words, tuples) == fun_kislyuk(words, tuples))

输出

True

以上功能的时间为:

%timeit fun_trrex(words, tuples)
11.3 ms ± 34.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit fun_kislyuk(words, tuples)
67.5 ms ± 1.75 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

数据是来自危险的大约 2K 个问题和 500 个随机选择的单词的列表。您可以找到 here 重现实验的资源。

更新

如果添加评论中提到的分组策略,时间改进会增加,下面是函数:

def fun_grouping_trrex(ws, ts):
    pattern = re.compile(tx.make(ws, left='', right=''))
    groups = defaultdict(list)
    for i, s in ts:
        groups[i].append(s)

    return {i for i, vs in groups.items() if any(pattern.search(v) for v in vs)}

和时间安排:

%timeit fun_trrex(words, tuples)
11.2 ms ± 61.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit fun_grouping_trrex(words, tuples)
4.96 ms ± 320 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit fun_kislyuk(words, tuples)
67.4 ms ± 1.47 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

分组 + trrex 的方法使您的性能提高了大约 10 倍 .但对最后一个结果持保留态度,因为它非常依赖于数据集。