1

Is there a way of me finding an item in array from a similar but not identical needle?

For example: I want to find 'Allan' in an array but pull out 'Alan'

Is this something that is possible?

esqew
  • 42,425
  • 27
  • 92
  • 132
Danny Peak
  • 29
  • 2
  • 4
    php functions: `levenshtein()` or `similar_text()` –  Oct 10 '18 at 20:49
  • The following post seems like it may be able to help: [filter values from an array similar to SQL LIKE '%search%' using PHP](https://stackoverflow.com/questions/5808923/filter-values-from-an-array-similar-to-sql-like-search-using-php) – Justin T. Oct 10 '18 at 20:52
  • Ah yes thanks, `levenshtein()` is exactly what i need! Don't know how i couldn't find this – Danny Peak Oct 10 '18 at 20:54
  • examples: https://ideone.com/Rlp3Kr –  Oct 10 '18 at 20:58
  • 1
    [Metaphone](http://php.net/manual/en/function.metaphone.php) is also a choice. I use a combination of both (metaphone and levenshtein) but in the DB :-p. levenshtein is actually somewhat inferior to metaphone, because metaphone can be calculated beforehand, which increases the performance. For example in the DB, you can store the metaphone value in a field, but the levenshtein value cannot be found until the search is done. – ArtisticPhoenix Oct 10 '18 at 21:13
  • @IdontDownVote Please consider posting this as answer. – esqew Oct 10 '18 at 21:17
  • I actually deal a lot with names, (at my JOB) if you can use something like Sphinx search it has a thing called "wordforms" [Docs](http://sphinxsearch.com/docs/current/conf-wordforms.html) This will let you match things like "Bill > William" which is Awesome (with a capital A). I haven't used it in production, but I have experimented a bit with it. To be honest it's about the only "easy" way to do it. One could map them in a php array, but that would be a chore. – ArtisticPhoenix Oct 10 '18 at 21:24

2 Answers2

0

You can try metaphone and similar_text function inside array_filter anonymous function.

 $items=array("trina","treena","allan","alan");
 $key="trina";
 $filteredItems = array_filter($items, function($elem) use($key){
    $s=similar_text(metaphone($elem),metaphone($key),$p);
    return ($p>80 && $elem!==$key) ; //if 80% similar
 });
 print_r($filteredItems);

output

Array ( [1] => treena )
sumit
  • 15,003
  • 12
  • 69
  • 110
  • I would use `metaphone` such as `metaphone($elem, 3)` so its the same length (just one of the reasons metaphone is better then soundx), and there is no need to use `===` on 2 strings. – ArtisticPhoenix Oct 10 '18 at 21:31
  • thanks mate , I have edited my answer . I am happy to delete it , if your answer is relevant – sumit Oct 10 '18 at 21:43
  • You can leave yours too, no worries. I do a lot of work with names and it's surprising the variation of them, something I never considered ... lol – ArtisticPhoenix Oct 10 '18 at 21:48
0

Using Metaphone

function soundsLike($needle, $haystack){
    $sounds = metaphone($needle);
    foreach($haystack as $item){
        if( $sounds == metaphone($item, strlen($sounds)))return $item;
    }
}

echo soundsLike('will', ["trina","treena","alan","allan","William"]);

Output

"William"

Sandbox

As I said in the comments for another answer, metaphone is better then soundx the key thing here is metaphone lets you set the length, which can be dynamically based on the length of your needle. Specifically strlen($sounds).

The reason this is better is take the above example.

 will = WL
 William = WLM

And WL != WLM however because we can set the length at 2 WL == WL.

-Note- this only returns the first result, but it would be trivial to extend it to find them all. Like this

function soundsLike($needle, $haystack){
    $sounds = metaphone($needle);
    $matches = [];
    foreach($haystack as $item){
        if( $sounds == metaphone($item, strlen($sounds))) $matches[]=$item;
    }
    return $matches;
}

print_r(soundsLike('al', ["trina","treena","alan","allan","William"]));

Output

Array(
   [0] => alan
   [1] => allan
)

Sandbox

ArtisticPhoenix
  • 21,464
  • 2
  • 24
  • 38