在文本中查找单词,非常慢的解决方案

时间:2018-10-28 12:16:08

标签: python python-3.x performance

我必须创建一个函数,该函数给定一个包含空格的串联单词文本,以及一个既包含出现的单词又出现在所述文本中的单词的列表。

我必须创建一个元组,其中包含一个新列表,该列表仅包含按出现顺序出现在文本中的单词和出现在文本中最多的单词。如果有两个单词出现次数最多,该函数将按字母顺序选择一个(如果单词看起来像"b"=3,"c"=3,"a"=1,,则它将选择"b"

我还必须修改原始列表,以使其仅包含文本中未包含的单词,而无需修改其顺序。

例如,如果我有

list=["tree","page","law","gel","sand"]
text="pagelawtreetreepagepagetree"`

那么元组将是

(["page","tree","law"], "page") 

列表将变为

list=["gel","sand"]

现在我已经完成了此功能,但是它的速度非常慢,有人可以帮忙吗?

ls=list

def es3(ls,text):
   d=[]
   v={}
   while text:
       for item in ls:
           if item in text[:len(item)]:
               text=text[len(item):]
               if item not in d:
                   d+=[item]
                   v[item]=1
               else:
                   v[item]+=1
   if text=="": 
       p=sorted(v.items())       
       f=max(p, key=lambda k: k[1])
       M=(d,f[0])
       for b in d:
           if b in lista:
               ls.remove(b)
       return (M)

1 个答案:

答案 0 :(得分:1)

在python中,字符串是不可变的-如果您对其进行修改,则会创建新对象。创建对象的时间/内存效率低下-几乎在所有情况下,最好使用列表代替。

通过创建k-text的所有可能k长度部分的列表,它们是您要查找的单词的(唯一)长度(列表中的3和4)您将创建所有可以计数和过滤的拆分,这些拆分不在您的单词集中:

# all 3+4 length substrings as list - needs 48 lookups to clean it up to whats important
['pag', 'page', 'age', 'agel', 'gel', 'gela', 'ela', 'elaw', 'law', 'lawt', 'awt', 
 'awtr', 'wtr', 'wtre', 'tre', 'tree', 'ree', 'reet', 'eet', 'eetr', 'etr', 'etre', 
 'tre', 'tree', 'ree', 'reep', 'eep', 'eepa', 'epa', 'epag', 'pag', 'page', 'age', 
 'agep', 'gep', 'gepa', 'epa', 'epag', 'pag', 'page', 'age', 'aget', 'get', 'getr', 
 'etr', 'etre', 'tre', 'tree']

对“ is A in B”检查使用集合也会使编码器更快-集合具有O(1)查找-列表花费的时间越长,元素越多(最坏的情况:n)。因此,您可以从k-长零件列表中删除所有与您要查找的词都不匹配的词(即'eter'

# whats left after the list-comprehension including the filter criteria is done
['page', 'gel', 'law', 'tree', 'tree', 'page', 'page', 'tree']

为了计算可迭代项,我使用collections.Counter-一种专门的字典..来计算事物。它是most_common()方法,返回按最先出现的顺序排序的元组(键,计数),我将其格式化为与您的OP匹配的返回值。

一个解决它重叠结果的版本:

from collections import Counter

def findWordsInText(words,text):
    words = set(words) # set should be faster for lookup
    lens = set(len(w) for w in words)

    # get all splits of len 3+4 (in this case) from text
    splitted = [text[i:i+ll] for i in range(len(text)-min(lens)) for ll in lens 
                if text[i:i+ll] in words] # only keep whats in words

    # count them
    counted = Counter(splitted)

    # set-difference
    not_in = words-set(splitted)

    # format as requested: list of words in order, most common word
    most_common = counted.most_common()
    ordered_in = ( [w for w,_ in most_common], most_common[0][0] )

    return list(not_in), ordered_in

words = ["tree","page","law","gel","sand"]

text = "pagelawtreetreepagepagetree"

not_in, found = findWordsInText(words,text)

print(not_in)
print(found)

输出:

['sand']
(['page', 'tree', 'gel', 'law'], 'page')