Maximus L Maximus L - 1 month ago 7
PHP Question

Get keys from multidimentional array by value

I need to get all "top level" keys from multidimensional array by searching the "bottom level" values. Here is an example of the array:

$list = array (
'person1' => array(
'personal_id' => '1',
'short_information' => 'string',
'books_on_hand' => array(
'Book 1',
'Book 2',
'Book 3',
)
),
'person2' => array(
'personal_id' => '2',
'short_information' => 'string',
'books_on_hand' => array(
'Book 4',
'Book 2',
'Book 5',
)
),
'person3' => array(
'personal_id' => '3',
'short_information' => 'string',
'books_on_hand' => array(
'Book 4',
'Book 2',
'Book 1',
'Book 3',
)
),
//etc...
);


I want to know all persons who have "Book 2" on hand. I can get that information by loop like this:

foreach ($list as $person => $info){
$check = array_search( 'Book 2', array_column($info, 'books_on_hand') );
if ( $check !== false ){
$results .= 'Name: '.$person;
$results .= 'ID: '.$info['personal_id'];
//get other infos other stuff, if necessary
}
}


The problem is, that
foreach
in this case is very heavy on memory and only grows more when array has a thousand+ entries. It needs to run through all of the persons, even if only 3 persons at the very top of the array have "Book 2".

I have been trying to optimize it by getting persons with "Book 2" using built-in functions like
array_search
,
array_keys
,
array_column
and only then run
foreach
for persons found, but I had no luck with getting "top level" keys.

Is it possible to optimize or use built-in function to search multidimensional array?

Answer

One way would be to filter it first. Now your result is structured like $list but it only contains elements with the needed book:

$find   = 'Book 2';
$result = array_filter($list, function($v) use($find) {
                                  return in_array($find, $v['books_on_hand']);  
                              });

If all you're interested in is the person key and personal_id then this:

$find   = 'Book 2';
$result = array_map(function($v) use($find) {
                       if(in_array($find, $v['books_on_hand'])) {
                           return $v['personal_id'];
                       }
                    }, $list);

Will return something like this for persons with the needed book:

Array
(
    [person1] => 1
    [person2] => 2
    [person3] => 3
)