Reputation: 838
For this nested array:
$status = array(
"house" => "OK",
"car" => array(
"car1" => "OK",
"car2" => "ERROR"
),
"boat" => "OK"
);
I want to know if a certain value "ERROR" exists at least once in the array. I don't care what key it's associated with, I just want to know if the $status array contains an "ERROR" status anywhere in it.
Is there a cleaner way to do this than just iterating over the elements with nested for loops?
Upvotes: 1
Views: 2785
Reputation: 21671
I actually wouldn't use array recursive. It falls short in a few key things you want to do. And while at first it may seem like a "shortcut" to what you want,if fails in a few key ways:
$all
array with nesting, because the keys that have an array as their value are never passed to the callback. This essentially flattens the array out.That said, honestly I wouldn't build the all
array because it's pointless as you already have that array, so there is no point copying it. As I said I don't think you really want to rebuild $all
but if you did you couldn't do it with array_walk_recursive
even if you wanted to...
Anyway.
$array = ['zero','one', 'two' => ['zoo' => 'foo']];
function checkRecursive($value, $array){
$x = false;
foreach($array as $v){
if(is_array($v)) $x = checkRecursive($value, $v); //recursive
if($v == $value || $x == true) return true;
}
return false;
}
echo checkRecursive('one', $array) ? "true\n" : "false\n";
echo checkRecursive('foo', $array) ? "true\n" : "false\n";
echo checkRecursive('bar', $array) ? "true\n" : "false\n";
prints
true
true
false
Test it
http://sandbox.onlinephpfunctions.com/code/78d0de421475b8e3104376c698027107e9b7e948
UPDATE I see you changed the question and while you say "value" your array says the "key"
$status = array(
"house" => "OK",
"car" => array(
"car1" => "OK",
"car2" => "OK"
),
"boat" => "OK"
);
Because all the values are the same. So if you really want to find the key instead then just change it to this
function checkRecursive($value, $array){
$x = false;
foreach($array as $k=>$v){
if(is_array($v)) $x = checkRecursive($value, $v); //recursive
if((string)$value == (string)$k || $x == true) return true;
}
return false;
}
A few things to note when checking for the keys, it's possible they will not always be strings, or that you will check using an unqoted number. In these cases PHP sometimes has a weird way of changing a string into an integer and non-numeric strings will come out as 0
. For example "1" = 1
but "one" = 0
when taken as an integer. Therefore if you have an array with a key of 0
and you check for one
it will match it because it will turn "one"
into a 0
.
You can solve this by casting everything to strings. Or by using the ===
strict type checking. I prefer the string method because checking with ===
would make 0 != "0"
so if you tried finding a key of 0
with "0"
it would say no match. This is true of other numbers. That is unless you plan on checking objects with it.
This is still an issue when looking for the "values" but it's less of one, because there you are not dealing with the native integer keys in an array, so there is a greater possibility you wouldn't encounter it.
It all has to do with PHP's loosely typed nature, it's a feature not a bug...
I put this small example togather:
echo '(int)"one": ';
echo (int)"one";
echo "\n";
echo "0 == 'one': " . (0 == "one" ? "true\n" : "false\n");
echo "1 == '1': " . (1 == "1" ? "true\n" : "false\n");
Outputs:
(int)"one": 0
0 == 'one': true
1 == '1': true
http://sandbox.onlinephpfunctions.com/code/df41f55251570a12d9ca693712bcdc785ad62f85
Upvotes: 3
Reputation: 111
You could use the function array_walk_recursive()
to get all the values with any level of nested array.
https://secure.php.net/manual/en/function.array-walk-recursive.php
<?php
$status = array(
"house" => "OK",
"car" => array(
"car1" => "OK",
"car2" => "OK"
),
"boat" => "OK"
);
$required = array();
array_walk_recursive($status, function ($value, $key) use (&$required){
$required[] = $value;
}, $required);
print '<pre>';
print_r($required);
print '</pre>';
?>
Output:
Array
(
[0] => OK
[1] => OK
[2] => OK
[3] => OK
)
Upvotes: 7