更快地进行列表查找?

时间:2017-12-17 19:11:03

标签: python loops python-3.5

我有一个文件,每行包含人名和包含演讲文本的文件。具有名称的文件非常大(250k行)按字母顺序排序,语音文件大约有1k行。我想要做的是查找我的文本文件中的名称,并从我的名称文件中替换每个出现的名称。 这是我的代码编辑:打开列表的with函数只执行一次。

members_list = []
with open(path, 'r') as l:
    for line in l.readlines():
        members_list.append(line.strip('\n'))

for member in self.members_list:
    if member in self.body:
        self.body = self.body.replace(member, '<member>' + member + '</member>')

此代码运行大约需要2.2秒,但因为我有很多语音文件(4.5k),所以总时间大约为3小时。 是否有可能加快速度?发电机是否可行?

1 个答案:

答案 0 :(得分:1)

目前,当您检查&#34;如果成员在self.body&#34;。

时,您会为250,000个名称中的每一个重读一次内存中的每个语音。

你需要解析一次语音体,找到整个单词,空格和标点符号。然后,您需要查看是否找到了名称,使用已知成员名称的线性时间查找,或者在最差的日志时间。

问题是你必须找到具有不同字长的成员名称。所以这是一个快速(并不是很好)的实现,我写了来处理检查最后三个单词。

# This is where you load members from a file. 
# set gives us linear time lookup
members = set()
for line in ['First Person', 'Pele', 'Some Famous Writer']:
    members.add(line)

# sample text
text = 'When Some Famous Writer was talking to First Person about Pele blah blah blah blah'
from collections import deque

# pretend we are actually parsing, but I'm just splitting. So lazy.
# This is why I'm not handling punctuation and spaces well, but not relevant to the current topic
wordlist = text.split()

# buffer the last three words
buffer = deque()

# TODO: loop while not done, but this sort of works to show the idea
for word in wordlist:
    name = None
    if len(buffer) and buffer[0] in members:
        name = buffer.popleft()

    if not name and len(buffer)>1:
        two_word_name = buffer[0] + ' ' + buffer[1]
        if two_word_name in members:
            name = two_word_name
            buffer.popleft()
            buffer.popleft()

    if not name and len(buffer)>2:
        three_word_name = buffer[0] + ' ' + buffer[1] + ' ' + buffer[2]
        if three_word_name in members:
            name = three_word_name
            buffer.popleft()
            buffer.popleft()
            buffer.popleft()

    if name:
        print ('<member>', name, '</member> ')

    if len(buffer) >2:
        print (buffer.popleft() + ' ')

    buffer.append(word)

# TODO handle the remaining words which are still in the buffer
print (buffer)

我只是想证明这个概念。这不会处理空格或标点符号。这根本没有处理结束 - 它需要在没有完成的情况下循环。它在解析时会创建一堆临时字符串。但它说明了解析一次的基本概念,即使在解析语音文本时速度非常慢,也可能超过搜索语音文本250,000次。

您要解析文本并检查集中名称的原因是您执行此操作一次。集合具有分摊的线性时间查找,因此检查成员中的名称是否更快。

如果我有机会,我可能会稍后编辑它,成为一个生成令牌的类,并在最后修复查找名称,但我并不打算将其作为您的最终代码。