0

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

方法一:

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")
4

5 回答 5

2

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

稍微调整一下:

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")
于 2012-09-17T12:14:28.960 回答
2

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

您正在寻找的是enumerate

with open('data') as f:
    d = dict((j[:-1],i) for i,j in enumerate(f,1))

还应该指出的是,在这两种情况下,如果您使用的函数搜索速度会更快,try/except前提是您要查找的索引通常可以找到。(在第一种情况下,它可能会更快,因为in它是订单N操作,.index列表也是如此)。

例如:

def search_dict(d, search_string):
    try:
        print "found at line {0}".format(d[search_string])
    except KeyError:
        print "string not found"

或列表:

def search_list(search_string):
    try:
        print "found at line {0}".format(li.indexOf(search_word)+1)
    except ValueError:
        print "string not found"
于 2012-09-17T12:16:56.613 回答
1

在阅读了 eumiro 和 mgilson 的答案后,我发布了这个。

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

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

有几种方法可以做到这一点,一种是制作一个守护程序来保存索引并使用前端脚本来查询它。在谷歌上搜索类似的东西python daemon client communication会给你实现这一点的指导——这是一种方法

于 2012-09-17T12:31:16.853 回答
0

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

如果您在文档中进行临时搜索,那么这两种方法都不起作用。为此,您需要使用 Lucene 之类的东西进行解析和索引。

于 2012-09-17T12:17:22.167 回答
0

另一个选择是使用 SQLite3 提供的 FTS ...(未经测试并假设您正在寻找全词,而不是单词的子字符串或其他类似的东西)

import sqlite3

# create db and table
db = sqlite3.connect(':memory:') # replace with file on-disk?
db.execute('create virtual table somedata using fts4(line)')

# insert the data
with open('yourfile.txt') as fin:
    for lineno, line in enumerate(fin):
        # You could put in a check here I guess...
        if somestring in line:
            print lineo # or whatever....
        # put row into FTS table
        db.execute('insert into somedata (line) values (?)', (line,))
    # or possibly more efficient
    db.executemany('insert into somedata (line) values (?)', fin)
db.commit()

look_for = 'somestring'
matches = db.execute('select rowid from somedata where line match ?', (look_for,) )
print '{} is on lines: {}'.format(look_for, ', '.join(match[0] for match in matches))

如果您只想要第一行,请添加limit 1到查询的末尾。

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

于 2012-09-17T12:51:04.567 回答