简体   繁体   English

在PHP中,在数组中搜索包含子字符串的值的快速方法是什么?

[英]In PHP, what is a fast way to search an array for values which contain a substring?

I have an array of street names sorted alphabetically that I have gathered from a web service. 我有一系列街道名称按字母顺序排序,我从网络服务收集。 This array exists on the server side. 该阵列存在于服务器端。

On the client side, a user starts typing the name of the street he lives on and AJAX is used to return a list of the closest match to the partial street name, plus the next 9 street names in the array (the list is updated while he is typing). 在客户端,用户开始键入他所居住的街道的名称,AJAX用于返回与部分街道名称最接近的匹配的列表,以及阵列中的下9个街道名称(列表更新时他在打字)。

For example, if the user typed "al", I would expect the results to be something like the following: 例如,如果用户键入“al”,我希望结果如下所示:

  • Albany Hwy 奥尔巴尼高速公路
  • Albens Vale Albens Vale
  • Alcaston Rd 阿尔卡斯顿路
  • Alex Wood Dr 亚力克伍德博士
  • Alice Rd 爱丽丝路
  • Allawah Ct Allawah Ct
  • Allen Rd 艾伦路
  • Alloway Pl Alloway Pl
  • Allwood Av Allwood Av
  • Alola St 阿洛拉街
  • Amanda Dr 阿曼达博士

This is my try at it: 这是我的尝试:

$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;
  }
}

Does anyone else know a faster way? 有没有其他人知道更快的方式?

Please note: I have no control over how this list is obtained from the database - it's from an external web service. 请注意:我无法控制如何从数据库中获取此列表 - 它来自外部Web服务。

Use preg_grep() : 使用preg_grep()

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

Note: this method like yours will be a brute force search. 注意:像你这样的方法将是一个强力搜索。 If you're searching a huge list of names (hundreds of thousands) or searching a huge number of times then you may need something better. 如果你正在搜索一个巨大的名单(数十万)或搜索很多次,那么你可能需要更好的东西。 For small data sets this is fine however. 对于小数据集,这很好。

I think what you're looking for is preg_grep() 我认为你要找的是preg_grep()

You can search either for elements starting with the input text: 您可以搜索以输入文本开头的元素:

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

or for elements that contain the text in any place: 或者对于在任何地方包含文本的元素:

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

or you can also anchor the search to the end but that doesn't look so useful 或者您也可以将搜索锚定到最后,但这看起来并不那么有用

The only way to get faster than looking through all the strings would be to have a data structure optimized for this kind of thing, a trie . 获得比查看所有字符串更快的唯一方法是为这种事物优化数据结构,即trie You may not have control over what the webservice gives you, but if you can cache the result on your server and reuse it for serving many requests, then building a trie and using that would be much faster. 您可能无法控制Web服务为您提供的内容,但如果您可以将结果缓存在服务器上并重复使用它来处理许多请求,那么构建trie并使用它会快得多。

Can't really tell if it is faster, but this is my version of it. 无法确定它是否更快,但这是我的版本。

$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);

This creates a weighted list of matches. 这将创建一个加权的匹配列表。 They are sorted according to the distance between the input string and the street name. 它们根据输入字符串和街道名称之间的距离进行排序。 0 represents a true match. 0代表真正的匹配。

Resulting array looks like this 结果数组看起来像这样

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

Where 0 => street name and 1 => levenshtein distance 其中0 =>街道名称和1 => levenshtein距离

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM