Home > Enterprise >  Filter array to keep elements where the key exists in the value string
Filter array to keep elements where the key exists in the value string

Time:01-26

I need to filter my flat, associative array of string-type values by checking if its key is found (case-sensitive) in its value as a substring. In other words, if an element's key is in the element's value, I want to retain the element in the output array.

I can craft a classic foreach() loop with calls of strpos(), but this feels very pedestrian. Is there a more modern/elegant way do this?

My code:

$array = [
    'needle' => 'needle in haystack text',
    'Need' => 'another needle',
    'fine' => 'refined',
    'found' => 'Foundation',
    '' => 'non-empty haystack',
    'missing' => 'not here',
    'This is 0 in a haystack!',
];

$result = [];
foreach ($array as $needle => $haystack) {
    if (strpos($haystack, $needle) !== false) {
        $result[$needle] = $haystack;
    }
}
var_export($result);

Output:

array (
  'needle' => 'needle in haystack text',
  'fine' => 'refined',
  '' => 'non-empty haystack',
  0 => 'This is 0 in a haystack!',
)

CodePudding user response:

From PHP5.6, array_filter() gained the ARRAY_FILTER_USE_BOTH flag. This makes array_filter() an equivalent functional-style technique.

Code: (Demo)

var_export(
    array_filter(
        $array,
        function($haystack, $needle) {
            return strpos($haystack, $needle) !== false;
        },
        ARRAY_FILTER_USE_BOTH
    )
);

One advantage of this is that $result doesn't need to be declared. On the other hand, despite the fact that it can technically be written as a one-liner, it would make a very long line of code -- something that puts the code near or over the soft character limit per line according to PSR-12 coding standards. So there is very little to compel you to change your code so far.

The good news is that PHP8 introduced str_contains() specifically to offer a clean, native, case-sensitive function to replace strpos() and its obligatory strict boolean false check.

Code: (Demo)

var_export(
    array_filter($array, 'str_contains', ARRAY_FILTER_USE_BOTH)
);

This returns the same desired output, is a functional-style, one-liner, and concisely spans just 59 characters. I would recommend this approach.

To understand what is happening, the verbose syntax with array_filter() where str_contains() is not called by its string name looks like this:

var_export(
    array_filter(
        $array,
        fn($haystack, $needle) => str_contains($haystack, $needle),
        ARRAY_FILTER_USE_BOTH
    )
);
  •  Tags:  
  • Related