Home > Mobile >  Filter an array of words by an array of single letters it should ONLY contain
Filter an array of words by an array of single letters it should ONLY contain

Time:07-20

I currently have two PHP arrays:

  1. array('a','c','r','r')
  2. array('carr','car','arc','ra','c','abc','do','aa','rr')

My desired result is:

array('carr','car','arc','ra','c','rr')

i.e. filtering out 'abc','do','aa' because I wish to filter out words that:

  1. don't contain a, c or r
  2. contain more/multiple a,c,r than I have in array 1.

I have tried array_filter() but I don't seem to be able to make it work.

CodePudding user response:

One way to do this:

Count how many times each letter occurs in your first array, using array_count_values.

Then in your array_filter callback function, split each word into individual letters, and also count how many times each of them occurs. Then loop over those counted letters. If the current letter does not occur in your letter-count-array, or its count is greater than that in your letter-count-array, return false.

$letters = ['a','c','r','r'];
$words = ['carr','car','arc','ra','c','abc','do','aa','rr'];

$letterCounts = array_count_values($letters);

$filtered = array_filter($words, function($word) use ($letterCounts) {
    $wordLetterCounts = array_count_values(mb_str_split($word));
    foreach($wordLetterCounts as $wordLetter => $count) {
        if(!isset($letterCounts[$wordLetter]) || $letterCounts[$wordLetter] < $count) {
            return false;
        }
    }
    return true;
});

var_dump($filtered);

CodePudding user response:

As you iterate the array of words, you can iterate the array of letters and make single-letter replacements. If all letters in the word are consumed, the word is saved.

A regular expression isn't actually necessary because the letter is literal, but preg_replace() offers a limiting parameter and str_replace() doesn't.

Code: (Demo)

$needles = ['a','c','r','r'];
$haystacks = ['carr','car','arc','ra','c','abc','do','aa','rr', 'rrr'];

$result = [];
foreach ($haystacks as $i => $haystack) {
    foreach ($needles as $needle) {
        $haystack = preg_replace("/$needle/", '', $haystack, 1);
    }
    if (!$haystack) {
        $result[] = $haystacks[$i];
    }
}
var_export($result);

The above can actually be boiled down to this: (Demo)

$regexes = array_map(fn($v) => "/$v/", $needles);
var_export(
    array_filter(
        $haystacks,
        fn($hay) => !preg_replace($regexes, '', $hay, 1)
    )
);
  • Related