提取匹配字符串的最快方法

时间:2018-04-28 19:41:52

标签: python algorithm search complexity-theory

我想搜索与列表中给定单词匹配的单词(下面的示例)。但是,有一个包含数百万字的列表。执行此搜索的最有效方法是什么?我在考虑对每个列表进行标记并将这些单词放在哈希表中。然后执行单词搜索/匹配并检索包含该单词的单词列表。从我所看到的是这个操作将采取O(n)操作。还有其他方法吗?可能没有使用哈希表?。

words_list = ['yek', 'lion', 'opt'];
# e.g. if we were to search or match the word "key" with the words in the list we should get the word "yek" or a list of words if there many that match 

此外,是否有可以执行高效搜索的python库或第三方软件包?

1 个答案:

答案 0 :(得分:1)

当你在这里指的是“匹配”时,并不完全清楚,但是如果你可以将其减少为身份比较,那么问题就会减少到设定查询,即O(1)时间。

例如,如果“匹配”表示“具有完全相同的字符集”:

words_set = {frozenset(word) for word in words_list}

然后,查找一个词:

frozenset(word) in words_set

或者,如果它意味着“具有完全相同的多字符字符”(即计算重复但忽略顺序):

words_set = {sorted(word) for word in words_list}

sorted(word) in words_set

...或者,如果您愿意:

words_set = {collections.Counter(word) for word in words_list}

collections.Counter(word) in words_set

无论哪种方式,关键(没有双关语......但也许它应该是)这里的想法是想出一个转换,将你的值(字符串)变成相同的值,如果它们匹配(一组字符,多字符字符,有序字符的有序列表等。然后,集合的整个点是它可以在恒定时间内查找等于您的值的值。

当然,转换列表需要O(N)时间(除非你只是在第一时间构建转换后的集合,而不是构建列表然后转换它),但是你可以反复使用它,它需要每次O(1)时间而不是O(N),这听起来像你在乎。

如果你需要找回匹配的单词,而不是只知道有一个单词,你仍然可以使用一个集合来执行此操作,但是使用dict更容易(如果你可以浪费一些空间): / p>

words_dict = {frozenset(word): word for word in words_list}

words_dict[frozenset(word)] # KeyError if no match

如果可能有多个匹配,只需将dict更改为multidict:

words_dict = collections.defaultdict(set)
for word in words_list:
    words_dict[frozenset(word)].add(word)

words_dict[frozenset(word)] # empty set if no match

或者,如果您明确希望它是一个列表而不是一个集合:

words_dict = collections.defaultdict(list)
for word in words_list:
    words_dict[frozenset(word)].append(word)

words_dict[frozenset(word)] # empty list if no match

如果你想不使用哈希表(为什么?),你可以使用搜索树或其他对数数据结构:

import blist # pip install blist to get it

words_dict = blist.sorteddict()
for word in words_list:
    words_dict.setdefault(word, set()).add(word)

words_dict[frozenset(word)] # KeyError if no match

这看起来几乎完全相同,除了将defaultdict包裹在blist.sorteddict周围并不是一件容易的事情 - 但这只需要几行代码。 (也许你真的想要一个KeyError而不是一个空集,所以我认为值得在某处用setdefault显示defaultdict和普通dict,所以你可以选择。)

但是在幕后,它使用混合B树变体而不是哈希表。虽然这是O(log N)时间而不是O(1),但在某些情况下它实际上比dict更快。