在巨大列表中查找/搜索的最有效方法(python)
Posted
技术标签:
【中文标题】在巨大列表中查找/搜索的最有效方法(python)【英文标题】:Most efficient way for a lookup/search in a huge list (python) 【发布时间】:2011-02-11 16:06:30 【问题描述】:-- 我刚刚解析了一个大文件,并创建了一个包含 42.000 个字符串/单词的列表。我想查询 [针对此列表] 以检查给定的单词/字符串是否属于它。所以我的问题是:
这种查找最有效的方法是什么?
第一种方法是对列表进行排序 (list.sort()
),然后使用
>> if word in list: print 'word'
这真的是微不足道的,我相信有更好的方法来做到这一点。我的目标是应用快速查找来查找给定字符串是否在此列表中。如果您对其他数据结构有任何想法,欢迎提出。然而,我现在想避免使用更复杂的数据结构,如 Tries 等。我有兴趣听到关于快速查找或任何其他 python 库方法的想法(或技巧),这些方法可能比简单的in
更快地进行搜索。
我也想知道搜索项的索引
【问题讨论】:
如果您预计稍后会进行复杂的查找 - 复杂我的意思不是微不足道的 - 我建议您将其存储在sqlite3
。
【参考方案1】:
不要创建list
,而是创建set
。它在恒定时间内进行查找。
如果您不想要集合的内存开销,请保留一个排序列表并使用 bisect
模块搜索它。
from bisect import bisect_left
def bi_contains(lst, item):
""" efficient `item in lst` for sorted lists """
# if item is larger than the last its not in the list, but the bisect would
# find `len(lst)` as the index to insert, so check that first. Else, if the
# item is in the list then it has to be at index bisect_left(lst, item)
return (item <= lst[-1]) and (lst[bisect_left(lst, item)] == item)
【讨论】:
非常感谢 THC4k 的详细回复。实际上,我正在考虑自己应用二进制搜索,但正如我所见,这就是 bisect 模块所做的事情,所以你节省了我的时间:)。再次感谢您的帮助。 @user229269,您锁定了帖子的错误部分!你可能想要set
,而不是list
。
@Mike Graham 我知道你在说什么,但我担心如果我使用集合我可能会遇到记忆问题,因为我的列表实际上是一个快速增长的单词列表,即将结束多达 100.000 个字符串甚至更多
@user229269, 100000 个项目并不多。对这么多项目使用set
而不是list
只会增加set 的数据确实增长到如此之大会导致内存问题,那么您可能需要考虑使用一种非常不同的技术,例如将数据存储在数据库中。
是的,实际上你 (@Mike Graham) 是对的 :) -- 我已经用过套装了。非常感谢让我重新考虑它【参考方案2】:
关于未考虑的集合与列表的一点:在“解析大文件”中,人们期望需要处理重复字/字符串。你根本没有提到这一点。
显然,将新单词添加到集合中会即时删除重复单词,而不会增加 CPU 时间或您的思考时间。如果你用一个列表来尝试它,它会以 O(N**2) 结束。如果您将所有内容附加到列表并在最后删除重复项,那么最聪明的方法是......鼓声......使用一组,并且列表的(小)内存优势可能会被重复。
【讨论】:
【参考方案3】:使用这个程序,看起来 dicts 是禁食,第二个,bi_contains 第三个列表:
from datetime import datetime
def ReadWordList():
""" Loop through each line in english.txt and add it to the list in uppercase.
Returns:
Returns array with all the words in english.txt.
"""
l_words = []
with open(r'c:\english.txt', 'r') as f_in:
for line in f_in:
line = line.strip().upper()
l_words.append(line)
return l_words
# Loop through each line in english.txt and add it to the l_words list in uppercase.
l_words = ReadWordList()
l_words = key: None for key in l_words
#l_words = set(l_words)
#l_words = tuple(l_words)
t1 = datetime.now()
for i in range(10000):
#w = 'ZEBRA' in l_words
w = bi_contains(l_words, 'ZEBRA')
t2 = datetime.now()
print('After: ' + str(t2 - t1))
# list = 41.025293 seconds
# dict = 0.001488 seconds
# set = 0.001499 seconds
# tuple = 38.975805 seconds
# list with bi_contains = 0.014000 seconds
【讨论】:
对 dicts 更快感到惊讶。下一个问题是生成“l_words”对象需要多长时间。 +1!以上是关于在巨大列表中查找/搜索的最有效方法(python)的主要内容,如果未能解决你的问题,请参考以下文章