查找大型列表是否包含特定字符串的最有效方法(Python)

时间:2009-05-16 12:01:37

标签: python string

我的文件大致包含所有英文单词(~60k字,~500k字符)。我想测试我收到的某个单词是否是“英文”(即如果这个确切的单词在列表中)。

在Python中执行此操作的最有效方法是什么?

简单的解决方案是将文件加载到列表中并检查该单词是否在该列表中。列表可以进行排序,我相信这会将复杂性降低到O(logn)。但是我不确定Python如何实现搜索列表,以及如果这么大的列表在内存中是否会有性能损失。我可以“滥用”我可以对单词长度设置上限的事实吗? (例如,说最长的一个是15个字符)。

请注意我在具有大量内存的计算机上运行应用程序,因此我对内存消耗的关注程度低于速度和CPU利用率。

由于

9 个答案:

答案 0 :(得分:16)

python Set就是你应该尝试的。

  

set对象是不同的hashable对象的无序集合。常见用途包括成员资格测试,从序列中删除重复项,以及计算数学运算,如交集,并集,差异和对称差异。

答案 1 :(得分:4)

示例Python代码:

L = ['foo', 'bar', 'baz'] # Your list
s = set(L)  # Converted to Set

print 'foo'  in s # True
print 'blah' in s # False

答案 2 :(得分:3)

Trie结构符合您的目的。毫无疑问,可以在那里找到Python实现......

答案 3 :(得分:2)

500k字符不是一个大的列表。如果您的列表中的项目是唯一的,并且您需要重复使用set,那么在最佳情况下会将复杂性降低到O(1)

答案 4 :(得分:2)

两件事:

Python'mutable set'类型有一个'add'方法(s.add(item)),所以你可以直接从大文件中读取(一行)到一个集合,而不使用列表作为中间数据结构。

Python允许您“挑选”数据结构,因此您可以将大集保存到文件中并节省重新启动集的时间。

其次,我一直在寻找一个英语单音节单词列表供我自己娱乐,但我发现的那些单词似乎是专有的。如果它不是侵入性的,我可以问一下你的英文单词列表是否可以被其他人获得?

答案 5 :(得分:2)

其他人已经使用set()给你内存方式,这通常是最快的方式,不应该为你的内存征税60k字数据集(最多几个MiB)。您应该能够使用:

构建您的集合
f=open('words.txt')
s = set(word.strip() for word in f)

但是,确实需要一些时间将集合加载到内存中。如果你正在检查很多单词,这没有问题 - 查找时间将超过它。但是,如果您只是为每个命令执行检查一个单词(例如,这是一个命令行应用程序,如“checkenglish [word]”),启动时间将比您只需搜索文件行所需的时间长按行。

如果这是您的情况,或者您拥有更大的数据集,则使用磁盘格式可能会更好。最简单的方法是使用dbm模块。使用以下命令从wordlist创建这样的数据库:

import dbm
f=open('wordlist.txt')
db = dbm.open('words.db','c')
for word in f:
    db[word] = '1'
f.close()
db.close()

然后您的程序可以通过以下方式检查成员身份:

db = dbm.open('words.db','r')
if db.has_key(word):
    print "%s is english" % word
else:
    print "%s is not english" % word

这将比设置查找慢,因为会有磁盘访问,但会比搜索更快,内存使用率低并且没有明显的初始化时间。

还有其他替代方法,例如使用SQL数据库(例如sqlite)。

答案 6 :(得分:1)

你基本上是在测试一个成员是否在一个集合中,对吗?

如果是这样,并且因为你说你有很多内存,为什么不在memcache中加载所有单词作为键,然后对每个单词,只检查它是否存在于memcache中。

或者使用bash使用的数据结构来自动完成命令名称 - 这在内存中是快速且高效的(无法记住名称)。

答案 7 :(得分:1)

如果内存消耗不是问题且单词不会改变,那么最快的方法是将所有内容放入哈希并以这种方式搜索。在Python中,这是Set。你将有恒定的时间查找。

答案 8 :(得分:0)

将列表转换为集合仅在您对数据重复运行此类查询时才有用,对列表进行排序和执行二进制搜索也是如此。如果您只想将数据从列表中提取一次,那么最好的选择是使用普通的线性搜索:

if 'foo' in some_list:
    do_something()

否则,最好的办法是使用已提到的集合或二进制搜索。您应该选择哪一个在很大程度上取决于数据的大小以及您可以节省多少内存。我被告知,真正的大型列表往往会从散列中获益更多,尽管占用的内存量可能非常昂贵。

最后,第三个选项是您可以将数据导入sqlite数据库并直接从中读取。 Sqlite非常快,它可以省去从文件加载整个列表的麻烦。 Python有一个非常好的内置sqlite library