簡體   English   中英

從另一個列表中搜索任何子字符串的字符串列表

[英]Search a list of strings for any sub-string from another list

鑒於這3個數據列表和關鍵字列表:

good_data1 = ['hello, world', 'hey, world']
good_data2 = ['hey, man', 'whats up']
bad_data = ['hi, earth', 'sup, planet']
keywords = ['world', 'he']

我正在嘗試編寫一個簡單的函數來檢查是否存在任何關鍵字作為數據列表中任何單詞的子字符串。 它應該返回True為good_data列表和虛假的bad_data

我知道如何以一種效率低下的方式做到這一點:

def checkData(data):
  for s in data:
    for k in keywords:
      if k in s:
        return True
  return False

你在找嗎?

any( k in s for k in keywords )

它更緊湊,但效率可能更低。

在你的例子中,只有很少的項目,這並不重要。 但如果您有幾千個項目的列表,這可能會有所幫助。

由於您不關心列表中的哪個元素包含關鍵字,因此您可以掃描整個列表(作為一個字符串),而不是一次掃描一個項目。 為此,您需要一個您知道在關鍵字中不會出現的連接字符,以避免誤報。 我在這個例子中使用換行符。

def check_data(data):
    s = "\n".join(data);
    for k in keywords:
        if k in s:
            return True

    return False

在我完全不科學的測試中,我的版本在大約30秒內檢查了5000個項目的列表100000次。 我在3分鍾后停止了你的版本 - 厭倦了等待發布=)

如果您有許多關鍵字,則可能需要嘗試后綴樹[1]。 插入三個數據列表中的所有單詞,在其終止節點中存儲每個單詞來自哪個列表。 然后,您可以非常快速地在樹上為每個關鍵字執行查詢。

警告:后綴樹實現起來非常復雜!

[1] http://en.wikipedia.org/wiki/Suffix_tree

您可以通過將關鍵字列表構建為正則表達式來改進問題。

這可能允許它們並行測試,但很大程度上取決於關鍵字是什么(例如,某些工作可以重復使用測試“hello”和“hell”,而不是從每個單詞的開頭搜索每個短語。

您可以執行以下操作:

import re
keyword_re = re.compile("|".join(map(re.escape, keywords)))

然后:

>>> bool(keyword_re.search('hello, world'))
True
>>> bool(keyword_re.search('hi, earth'))
False

(它實際上將返回找到的匹配對象,如果沒有找到則返回None - 如果您需要知道哪個關鍵字匹配,這可能很有用)

但是,這取得多少(如果有的話)將取決於關鍵字。 如果您只有一兩個,請保持當前的方法。 如果你有一個大的列表,可能值得進行分析和分析,看看哪個表現更好。

[編輯]作為參考,以下是這些方法對您的示例的作用:

               good1   good2  good3   bad1   bad2
original     : 0.206   0.233  0.229   0.390   63.879
gnud (join)  : 0.257   0.347  4.600   0.281    6.706
regex        : 0.766   1.018  0.397   0.764  124.351
regex (join) : 0.345   0.337  3.305   0.481   48.666

顯然,對於這種情況,你的方法比正則表達式要好得多。 這種情況是否總是如此取決於關鍵字的數量和復雜性以及將要檢查的輸入數據。 對於大量關鍵字,冗長列表或很少匹配的短語,正則表達式可能效果更好,但確實可以獲得計時信息,並且可能首先嘗試更簡單的優化(例如將最常用的單詞移到關鍵字列表的前面)。 有時最簡單的方法確實是最好的。

[Edit2]使用gnud的解決方案更新了表格,並在應用正則表達式之前采用了類似的方法。 我還添加了2個新測試:

good_data3 = good_data2 * 500  # 1000 items, the first of which matches.
bad_data2 = bad_data * 500     # 1000 items, none of which matches.

其中顯示了各種優點和缺點。 當立即找到匹配時,加入確實會更糟(因為加入列表時總是付費的,前期成本 - 這是線性搜索方法的最佳情況),但是對於非匹配列表,它執行更好。 當有在list.case大量的項目) 好得多。

我認為這是非常有效和清晰的,盡管你可以使用map()來避免許多巢。 對於更大的列表,我同意羅斯對字典的看法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM