Python 关于频繁搜索,以下哪种数据结构是最好的?

Python 关于频繁搜索,以下哪种数据结构是最好的?,python,performance,list,optimization,dictionary,Python,Performance,List,Optimization,Dictionary,我有一个包含一些内容的文本文件。我需要经常搜索此内容。我有以下两个选择,哪一个是最好的(通过更快的执行) 方法1: def search_list(search_string): if search_word in li: print "found at line ",li.indexOf(search_word)+1 if __name__="__main__": f=open("input.txt","r") li=[] for i in f

我有一个包含一些内容的文本文件。我需要经常搜索此内容。我有以下两个选择,哪一个是最好的(通过更快的执行)

方法1:

def search_list(search_string):
    if search_word in li:
        print "found at line ",li.indexOf(search_word)+1

if __name__="__main__":
    f=open("input.txt","r")
    li=[]
    for i in f.readlines():
        li.append(i.rstrip("\n"))
    search_list("appendix")
def search_dict(search_string):
    if d.has_key(search_word):
        print "found at line ",d[search_word]

if __name__="__main__":
    f=open("input.txt","r")
    d={}
    for i,j in zip(range(1,len(f.readlines())),f.readlines()):
        d[j.rstrip("\n")]=i
    search_dict("appendix")
方法2:

def search_list(search_string):
    if search_word in li:
        print "found at line ",li.indexOf(search_word)+1

if __name__="__main__":
    f=open("input.txt","r")
    li=[]
    for i in f.readlines():
        li.append(i.rstrip("\n"))
    search_list("appendix")
def search_dict(search_string):
    if d.has_key(search_word):
        print "found at line ",d[search_word]

if __name__="__main__":
    f=open("input.txt","r")
    d={}
    for i,j in zip(range(1,len(f.readlines())),f.readlines()):
        d[j.rstrip("\n")]=i
    search_dict("appendix")

如果您经常这样做,那么第二种方法会更快(您已经构建了类似于索引的东西)

只要稍微调整一下:

def search_dict(d, search_string):
    line = d.get(search_string)
    if line:
        print "found at line {}".format(line)
    else:
        print "string not found"

d = {}
with open("input.txt", "r") as f:
    for i, word in enumerate(f.readlines(), 1):
        d[word.rstrip()] = i
search_dict(d, "appendix")

如果您经常这样做,那么第二种方法会更快(您已经构建了类似于索引的东西)

只要稍微调整一下:

def search_dict(d, search_string):
    line = d.get(search_string)
    if line:
        print "found at line {}".format(line)
    else:
        print "string not found"

d = {}
with open("input.txt", "r") as f:
    for i, word in enumerate(f.readlines(), 1):
        d[word.rstrip()] = i
search_dict(d, "appendix")

对于频繁的搜索,字典肯定更好(前提是你有足够的内存来存储行号),因为键是散列的,并在O(1)操作中查找。但是,您的实现将无法工作。第一个
f.readlines()
将耗尽文件对象,第二个
f.readlines()
将不会读取任何内容

您需要的是:


还应该指出的是,在这两种情况下,如果您使用
try/except
,则执行搜索的功能将更快,前提是您要查找的索引通常都可以找到。(在第一种情况下,它可能更快,因为
In
是一个顺序
N
操作,列表的
.index
也是如此)

e、 g:

或列表:

def search_list(search_string):
    try:
        print "found at line {0}".format(li.indexOf(search_word)+1)
    except ValueError:
        print "string not found"

对于频繁的搜索,字典肯定更好(前提是你有足够的内存来存储行号),因为键是散列的,并在O(1)操作中查找。但是,您的实现将无法工作。第一个
f.readlines()
将耗尽文件对象,第二个
f.readlines()
将不会读取任何内容

您需要的是:


还应该指出的是,在这两种情况下,如果您使用
try/except
,则执行搜索的功能将更快,前提是您要查找的索引通常都可以找到。(在第一种情况下,它可能更快,因为
In
是一个顺序
N
操作,列表的
.index
也是如此)

e、 g:

或列表:

def search_list(search_string):
    try:
        print "found at line {0}".format(li.indexOf(search_word)+1)
    except ValueError:
        print "string not found"
第一个是O(n);第二个是O(1),但它需要在键上搜索。我会选第二个

如果您在文档中进行临时搜索,则两者都不起作用。为此,您需要使用类似Lucene的东西进行解析和索引。

第一个是O(n);第二个是O(1),但它需要在键上搜索。我会选第二个


如果您在文档中进行临时搜索,则两者都不起作用。为此,您需要使用Lucene之类的工具进行解析和索引。

我在阅读了eumiro和mgilson的答案后发布了这篇文章

如果您在命令行上比较两种方法,我认为您会发现第一种方法更快。其他答案说第二种方法更快,但它们基于这样一个前提,即在建立索引后,您将对文件进行多次搜索。如果从命令行按原样使用它们,则不会

建立索引比直接搜索字符串要慢,但是一旦建立了索引,搜索就可以很快完成,弥补了建立索引所花费的时间。如果只使用一次,则会浪费额外的时间,因为当程序完成时,索引将被丢弃,并且必须在下次运行时重新生成。您需要在两次查询之间将创建的索引保存在内存中,这样才能获得回报


有几种方法可以做到这一点,一种是制作一个守护进程来保存索引,并使用前端脚本来查询它。在谷歌上搜索类似于
python守护进程客户端通信的东西将为您提供实现这一点的指导--

我在阅读了eumiro和mgilson的答案后发布了这篇文章

如果您在命令行上比较两种方法,我认为您会发现第一种方法更快。其他答案说第二种方法更快,但它们基于这样一个前提,即在建立索引后,您将对文件进行多次搜索。如果从命令行按原样使用它们,则不会

建立索引比直接搜索字符串要慢,但是一旦建立了索引,搜索就可以很快完成,弥补了建立索引所花费的时间。如果只使用一次,则会浪费额外的时间,因为当程序完成时,索引将被丢弃,并且必须在下次运行时重新生成。您需要在两次查询之间将创建的索引保存在内存中,这样才能获得回报


有几种方法可以做到这一点,一种是制作一个守护进程来保存索引,并使用前端脚本来查询它。在google上搜索类似于
python守护进程客户端通信的东西将为您提供实现这一点的指导--.

另一个选择是使用SQLite3提供的FTS。。。(未经测试,假设你在寻找完整的单词,而不是单词的子串或其他类似的东西)

如果只需要第一行,则在查询末尾添加
limit 1


您还可以使用
mmap
映射文件,然后使用
.find
方法获取字符串的最早偏移量,然后假设它不是
-1
(即,未找到-比方说123456),然后执行映射文件[:123456]。计数('\n')+1以获取行号。

另一个插入选项是使用SQLite3提供的FTS。。。(未经测试,假设你在寻找完整的单词,而不是单词的子串或其他类似的东西)

如果只需要第一行,则在查询末尾添加
limit 1

您还可以查看使用
mmap
映射文件,然后使用
.find
方法获取字符串的最早偏移量,然后假设它不是
-1
(即,未找到-让我们来看看)