2012-12-16 165 views
-1

我有一列名字,我試圖從字符串列表中取出。我一直得到誤判,如部分匹配。另一個警告是,我希望它也可以在適用的情況下獲取姓氏。基於另一個列表中的值搜索列表

names = ['Chris', 'Jack', 'Kim'] 
target = ['Chris Smith', 'I hijacked this thread', 'Kimberly','Christmas is here', 'CHRIS'] 

desired_output = ['Chris Smith', 'Kimberly', 'CHRIS'] 

我試過這段代碼:

[i for e in names for i in target if i.startswith(e)] 

這不出所料返回克里斯·史密斯,聖誕節是在這裏,和金佰利。

我該如何做到最好?使用正則表達式還是可以用列表解析來完成?性能可能是一個問題,因爲實名名單長約88萬個名字。

(Python 2.7版)

編輯:我已經意識到我在這個例子中的標準是不現實的因爲想包括金佰利同時排除聖誕節是這裏的不可能的要求。爲了緩解這個問題,我發現了一個更完整的名單,其中將包括變體(包括Kim和Kimberly)。

+4

爲什麼'CHRIS'出現在輸出中,而不是'我劫持了這個線程'? –

+0

到目前爲止您嘗試了哪些方法? –

+0

如果輸入''Kimberly'',那麼爲什麼'聖誕節在這裏'缺失? –

回答

1

完全猜(再一次),因爲我看不到你怎麼就不能有Christmas is here給出任何合理的標準:

這將匹配具有與名稱的字開頭的單詞的任何目標...

names = ['Chris', 'Jack', 'Kim'] 
target = ['Chris Smith', 'I hijacked this thread', 'Kimberly','Christmas is here', 'CHRIS'] 

import re 
matches = [targ for targ in target if any(re.search(r'\b{}'.format(name), targ, re.I) for name in names)] 
print matches 
# ['Chris Smith', 'Kimberly', 'Christmas is here', 'CHRIS'] 

如果將其更改爲\b{}\b' - then you'll get ['Chris Smith', 'CHRIS']所以你失去Kim ...

+0

這似乎是最緊湊和最優雅的解決方案。根據我根據我的OP中的編輯更改的標準,我只是在搜索模式的末尾添加了另一個\ b – ChrisArmstrong

0

工作的呢?

names = ['Chris', 'Jack', 'Kim'] 
target = ['Chris Smith', 'I hijacked this thread', 'Kimberly','Christmas is here', 'CHRIS'] 

res = [] 
for tof in target: 
    for name in names: 
     if tof.lower().startswith(name.lower()): 
      res.append(tof) 
      break 
print res 
0

沒有放棄比賽「的聖誕節是在這裏」,因爲它可能無法爲系統,以確定是否聖誕節是一個名稱或別的東西沒有確定的方式。相反,如果你想加快這個過程,你可以嘗試這種O(n)方法。 我還沒有計時,但肯定比您的或建議的解決方案更快。

from difflib import SequenceMatcher 
names = ['Chris', 'Jack', 'Kim'] 
target = ['Chris Smith', 'I hijacked this thread', 'Kimberly','Christmas is here', 'CHRIS'] 
def foo(names, target): 
    #Create a generator to search the names 
    def bar(names, target): 
      #which for each target 
     for t in target: 
        #finds the matching blocks, a triplet, (i, j, n), and means that a[i:i+n] == b[j:j+n] 
      match = SequenceMatcher(None,names, t).get_matching_blocks()[0] 
        #match.size == 0 means no match 
        #and match.b > 0 means match does not happens at the start 
      if match.size > 0 and match.b == 0: 
          #and generate the matching target 
       yield t 
    #Join the names to create a single string 
    names = ','.join(names) 
    #and call the generator and return a list of the resultant generator 
    return list(bar(names, target)) 

>>> foo(names, target) 
['Chris Smith', 'Kimberly', 'Christmas is here', 'CHRIS'] 
0

根據你的描述,我得到的規則是:

  1. 忽略的情況;
  2. 目標單詞必須以關鍵字開頭。
  3. 如果目標單詞不完全是關鍵詞,那麼目標單詞必須是句子中唯一的單詞。

試試這個:

names = ['Chris', 'Jack', 'Kim'] 
target = ['Chris Smith', 'I hijacked this thread', 'Kimberly','Christmas is here', 'CHRIS'] 
desired_output = ['Chris Smith', 'Kimberly', 'CHRIS'] 

actual_output = [] 
for key in names: 
    for words in target: 
     for word in words.split(): 
      if key.lower() == word.lower(): 
       actual_output.append(words) 
      elif key.lower() == word.lower()[:len(key)] and len(words.split()) == 1: 
       actual_output.append(words) 
print(actual_output) 

它將輸出EXACTLY爲所需輸出(順便說一句,你確定你真的想要嗎?)。不要因三層環路而感到沮喪。如果你有N個名字和M個句子,並且每個句子中的單詞數量是有限的,那麼這個代碼的複雜性是O(mn),這不可能是更好的。

相關問題