2010-01-21 130 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

相关问题