2010-01-21 127 views
5

我有一系列按字母順序排序的街道名稱,這些街道名稱是從Web服務收集的。該數組存在於服務器端。在PHP中,如何快速搜索包含子字符串的值的數組?

在客戶端,用戶開始鍵入他住的街道名稱,AJAX用於返回與部分街道名稱最接近的匹配列表,以及數組中接下來的9個街道名稱(列表在他打字時更新)。

例如,如果用戶鍵入「人」,我希望的結果是類似以下內容:

  • 奧爾巴尼高速公路
  • Albens谷
  • Alcaston路
  • 亞歷克斯·伍德博士
  • 愛麗絲路
  • Allawah的Ct
  • 艾倫路
  • 阿洛韋PL
  • 奧爾伍德大道
  • Alola聖
  • 阿曼達博士

這是我嘗試它:

$matches = array(); 
for($i = 0; $i < count($streetNames); $i++) 
{ 
    if((stripos($streetNames, $input) === 0 && count($matches) == 0) || count($matches) < 10){ 
    $matches[] = $streetNames[$i]; 
    } else { 
    break; 
    } 
} 

有誰知道還有一個更快的方法?

請注意:我無法控制如何從數據庫中獲取此列表 - 它來自外部Web服務。

+0

嘛,找出最快的* *的方式,你必須把它基準來確定。但是,如果這是來自外部的web服務,那麼建立到web服務的連接將比任何你得到答案的代碼慢。 – Gordon 2010-01-21 09:04:55

+0

是的,我已經通過緩存24小時從Web服務器返回的數據。我們市的街道名稱一般不會有太大的變化 - 但是有很多發展和新的街道一直在出現,所以24小時看起來好像是一段很長的時間。 – 2010-01-22 00:00:45

回答

4

獲得比查看所有字符串更快的唯一方法是爲這種事情優化數據結構,trie。您可能無法控制Web服務爲您提供什麼,但是如果您可以將結果緩存到服務器上並將其重用以提供多個請求,那麼構建一個trie並使用它會快得多。

+0

有趣的,因爲我實際上是從Web服務器緩存數據。我會毫不猶豫地看看這個:) – 2010-01-22 00:02:03

+0

伴侶,傳說中的迴應!發現一個很好的php資源:http://phpir.com/tries-and-wildcards – 2010-01-22 00:12:02

4

我想你要找的是什麼preg_grep()

可以搜索無論是開始輸入文本元素:

$result = preg_grep('/^$input/', $streetNames); 

或包含在任何地方的文本元素:

$result = preg_grep('/$input/', $streetNames); 

或者您也可以將搜索錨定到最後但看起來並不那麼有用

+0

謝謝你的回答,我從來沒有聽說過preg_grep。雖然我不會在這種情況下使用它,但它看起來非常方便,我將在稍後將它歸檔:) – 2010-01-22 00:13:35

5

使用preg_grep()

$matches = preg_grep('/al/', $streetNames); 

注:像你這種方法將是一個強力搜索。如果你正在搜索一個龐大的名單(數十萬)或搜索很多次,那麼你可能需要更好的東西。對於小數據集,這是很好的。

+0

感謝cletus。雖然我不會在這個特定的實例中使用這種方法,但您已經將我的眼睛睜開了,否則我始終忽略了這個功能。我一定會在賽道上的某處使用它。再次感謝:) – 2010-01-22 00:14:50

+0

這將永遠不會是一個快速的方式:| – s3v3n 2012-02-23 15:41:34

4

真的不知道它是否更快,但這是我的版本。

$input = 'al'; 
$matches = array_filter($streetNames, create_function('$v','return (stripos($v,'.$input.') !== false ? true : false);')); 
$weight = array_map(create_function('$v','return array($v,levenshtein('.$input.',$v));'),$matches); 
uasort($weight, create_function('$a,$b', 'if ($a[1] == $b[1]) {return 0;} return ($a[1] < $b[1]) ? -1 : 1;')); 
$weight = array_slice($weight, 0, 10); 

這創建了一個加權匹配列表。它們根據輸入字符串和街道名稱之間的距離進行排序。 0代表真正的匹配。

結果數組看起來像這樣

array (
    0 => 
    array (
    0 => 'Alola St', 
    1 => 7, 
), 
    1 => 
    array (
    0 => 'Allen Rd', 
    1 => 7, 
) 
) 

其中0 =>街道名稱和1 => Levenshtein距離

+0

嘿,很好的工作我喜歡你的加權系統:) – 2010-01-22 00:12:36

+0

對我來說,一個自動完成是不完整的沒有這樣的權重或任何你想打電話它。但當然,這不是唯一的方法。只是一個概念的快速證明。 – 2010-01-22 08:43:13

相關問題