How to search by key=>value in a multidimensional array in PHP
Solution 1
Code:
function search($array, $key, $value)
{
$results = array();
if (is_array($array)) {
if (isset($array[$key]) && $array[$key] == $value) {
$results[] = $array;
}
foreach ($array as $subarray) {
$results = array_merge($results, search($subarray, $key, $value));
}
}
return $results;
}
$arr = array(0 => array(id=>1,name=>"cat 1"),
1 => array(id=>2,name=>"cat 2"),
2 => array(id=>3,name=>"cat 1"));
print_r(search($arr, 'name', 'cat 1'));
Output:
Array
(
[0] => Array
(
[id] => 1
[name] => cat 1
)
[1] => Array
(
[id] => 3
[name] => cat 1
)
)
If efficiency is important you could write it so all the recursive calls store their results in the same temporary $results
array rather than merging arrays together, like so:
function search($array, $key, $value)
{
$results = array();
search_r($array, $key, $value, $results);
return $results;
}
function search_r($array, $key, $value, &$results)
{
if (!is_array($array)) {
return;
}
if (isset($array[$key]) && $array[$key] == $value) {
$results[] = $array;
}
foreach ($array as $subarray) {
search_r($subarray, $key, $value, $results);
}
}
The key there is that search_r
takes its fourth parameter by reference rather than by value; the ampersand &
is crucial.
FYI: If you have an older version of PHP then you have to specify the pass-by-reference part in the call to search_r
rather than in its declaration. That is, the last line becomes search_r($subarray, $key, $value, &$results)
.
Solution 2
How about the SPL version instead? It'll save you some typing:
// I changed your input example to make it harder and
// to show it works at lower depths:
$arr = array(0 => array('id'=>1,'name'=>"cat 1"),
1 => array(array('id'=>3,'name'=>"cat 1")),
2 => array('id'=>2,'name'=>"cat 2")
);
//here's the code:
$arrIt = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr));
foreach ($arrIt as $sub) {
$subArray = $arrIt->getSubIterator();
if ($subArray['name'] === 'cat 1') {
$outputArray[] = iterator_to_array($subArray);
}
}
What's great is that basically the same code will iterate through a directory for you, by using a RecursiveDirectoryIterator instead of a RecursiveArrayIterator. SPL is the roxor.
The only bummer about SPL is that it's badly documented on the web. But several PHP books go into some useful detail, particularly Pro PHP; and you can probably google for more info, too.
Solution 3
<?php
$arr = array(0 => array("id"=>1,"name"=>"cat 1"),
1 => array("id"=>2,"name"=>"cat 2"),
2 => array("id"=>3,"name"=>"cat 1")
);
$arr = array_filter($arr, function($ar) {
return ($ar['name'] == 'cat 1');
//return ($ar['name'] == 'cat 1' AND $ar['id'] == '3');// you can add multiple conditions
});
echo "<pre>";
print_r($arr);
?>
Ref: http://php.net/manual/en/function.array-filter.php
Solution 4
Came back to post this update for anyone needing an optimisation tip on these answers, particulary John Kugelman's great answer up above.
His posted function work fine but I had to optimize this scenario for handling a 12 000 row resultset. The function was taking an eternal 8 secs to go through all records, waaaaaay too long.
I simply needed the function to STOP searching and return when match was found. Ie, if searching for a customer_id, we know we only have one in the resultset and once we find the customer_id in the multidimensional array, we want to return.
Here is the speed-optimised ( and much simplified ) version of this function, for anyone in need. Unlike other version, it can only handle only one depth of array, does not recurse and does away with merging multiple results.
// search array for specific key = value
public function searchSubArray(Array $array, $key, $value) {
foreach ($array as $subarray){
if (isset($subarray[$key]) && $subarray[$key] == $value)
return $subarray;
}
}
This brought down the the task to match the 12 000 records to a 1.5 secs. Still very costly but much more reasonable.
Solution 5
if (isset($array[$key]) && $array[$key] == $value)
A minor imporvement to the fast version.
Related videos on Youtube
Admin
Updated on January 28, 2022Comments
-
Admin over 2 years
Is there any fast way to get all subarrays where a key value pair was found in a multidimensional array? I can't say how deep the array will be.
Simple example array:
$arr = array(0 => array(id=>1,name=>"cat 1"), 1 => array(id=>2,name=>"cat 2"), 2 => array(id=>3,name=>"cat 1") );
When I search for key=name and value="cat 1" the function should return:
array(0 => array(id=>1,name=>"cat 1"), 1 => array(id=>3,name=>"cat 1") );
I guess the function has to be recursive to get down to the deepest level.
-
kronwied over 13 yearsThis works like a charm and I plan use it again for similar problems :D The only weird part is in the foreach and using the getSubIterator function on the RecursiveIteratorIterator instead of the $sub variable. I thought it was a typo at first but it's the right way! thanks Jared.
-
stefgosselin almost 13 yearsActually this prevents it from throwing warnings when the key is not set. Not so minor! -> +1'ed.
-
codercake over 12 yearsagreed, being able to actually glance through the php error log for major errors and not have it polluted with warnings is the way to go in my opinion.
-
trante about 12 yearsThank you for solution. Where do we get the "id"? From $outputArray?
-
Drew over 11 yearsThis answer should be correct. Although the brute force search method will do it, this is much less resource intensive.
-
Mahesh.D almost 11 yearsThanks,very straight forward solution,but don't know about performance ??.
-
Awena almost 9 yearsthis one is faster than Jhon/Jared's answer (0.0009999275207519) vs (0.0020008087158203).. Well this test is specific to my case and environment.. Im sticking with this, thanks stefgosselin
-
orrd almost 9 yearsThis is a good solution if you want to search an array that is only one level deep, but this particular question was about searching recursively into a deep array ("the function has to be recursive to get down to the deepest level").
-
orrd almost 9 yearsIt should be noted that what you're suggesting only makes sense if you're searching the same array many times. It takes far longer to go through the trouble of sorting it (O(n log n)) than it does to simply do a linear search for the value (O(n)). But once it's sorted, sure, then a binary search would be faster.
-
orrd almost 9 yearsI should also add that using objects instead of arrays may be a useful abstraction, but you could also do a binary search on an array if the array is sorted. You don't need to use objects to sort an array or to do a binary search on it.
-
shyammakwana.me over 8 yearsmy case is different but got hint from your answer.
-
Fr0zenFyr over 8 yearshow to unset the found element(could be a sub-array) from original array?
-
Rich Benner about 7 yearsCould you expand on this answer? Code only answers don't explain what you're actually doing.
-
mickmackusa over 6 yearsPlease update your question with the intent to educate.
-
Giovanny Gonzalez over 5 yearsThis is functional for only find Key, This works for me.
-
mickmackusa over 4 yearsThis is not a complete solution and so is more of an "Attempt To Respond To Another Post" and "Not An Answer".
-
clockw0rk almost 3 yearsit would only take a single operation for needle @ [100][1] if anybody used correct implemented multithreading. start a thread from [0][0] forward, from [100][1] backward, from [50][1] backward and from [50][0] forward. you can basically reduce search time by adding more threads as long as your processor does not meltdown ^^