Check If a "Run-Time" Multidimensional Array Key Exists

Check if a “run-time” multidimensional array key exists

LOL actually this was just one line of code added there =/

For a moment the references confused me a bit.

Here the code :

function _c($key,$value) {
global $c;

$array = &$c;
$keys = explode(' ',$key);

$setValue = false;
for($i=0;$i<count($keys);$i++) {
$v = $keys[$i];

//> If setValue is already = true we don't need to check it again
if (!$setValue && !array_key_exists($v,$array))
$setValue = true;

$array = &$array[$v];
}

if ($setValue)
$array = $value;
}

//> Usage _c('lib template engine',true);

Check if a run-time multidimensional array key exists

function checkKey($array) {
$args = func_get_args();
for ($i = 1; $i < count($args); $i++) {
if (!isset($array[$args[$i]]))
return false;
$array = &$array[$args[$i]];
}
return true;
}

Usage:

checkKey($config, 'lib', 'template', 'engine');
checkKey($config, 'genericSetting');

how to check if a specific array key is exist in multidimensional array

Super hacky solution:

function array_key_exists_recursive($array, $key) {
return strpos(json_encode($array), "\"" . $key . "\":") !== false;
}

Better solution:

$array = ['a' => ['b' => 'c']];
function array_key_exists_recursive($key, $array) {
if (array_key_exists($key, $array)) {
return true;
}
foreach($array as $k => $value) {
if (is_array($value) && array_key_exists_recursive($key, $value)) {
return true;
}
}
return false;
}

var_dump(array_key_exists_recursive('b', $array));

How to check if multiple array keys exists

If you only have 2 keys to check (like in the original question), it's probably easy enough to just call array_key_exists() twice to check if the keys exists.

if (array_key_exists("story", $arr) && array_key_exists("message", $arr)) {
// Both keys exist.
}

However this obviously doesn't scale up well to many keys. In that situation a custom function would help.

function array_keys_exists(array $keys, array $arr) {
return !array_diff_key(array_flip($keys), $arr);
}

in_array() and multidimensional array

in_array() does not work on multidimensional arrays. You could write a recursive function to do that for you:

function in_array_r($needle, $haystack, $strict = false) {
foreach ($haystack as $item) {
if (($strict ? $item === $needle : $item == $needle) || (is_array($item) && in_array_r($needle, $item, $strict))) {
return true;
}
}

return false;
}

Usage:

$b = array(array("Mac", "NT"), array("Irix", "Linux"));
echo in_array_r("Irix", $b) ? 'found' : 'not found';

How can I test that a key does NOT exist at different levels of a multidimensional array using data providers?

As far as I know Phpunit does not offer an assertion for an array key recursively.

You can extend Phpunit with your own assertions, but I would start lightly and add a private helper method to the test-case that returns a bool whether or not the array as the key recursively (check existing Q&A material like Search for a key in an array, recursively and others on how to check an array for a key recursively), and then do an assertion for false like:

$this->assertFalse(
$this->arrayHasKeyRecursive($array, $expected),
"key must not exist"
);

just keep in mind when you write code to support your tests, to make it quite dumb (and sometimes you need to put helper routines under test as well so that your tests do not lie to you on bugs).


Cross reference

  • Testing iterables in PHPUnit

Checking if array is multidimensional or not?

The short answer is no you can't do it without at least looping implicitly if the 'second dimension' could be anywhere. If it has to be in the first item, you'd just do

is_array($arr[0]);

But, the most efficient general way I could find is to use a foreach loop on the array, shortcircuiting whenever a hit is found (at least the implicit loop is better than the straight for()):

$ more multi.php
<?php

$a = array(1 => 'a',2 => 'b',3 => array(1,2,3));
$b = array(1 => 'a',2 => 'b');
$c = array(1 => 'a',2 => 'b','foo' => array(1,array(2)));

function is_multi($a) {
$rv = array_filter($a,'is_array');
if(count($rv)>0) return true;
return false;
}

function is_multi2($a) {
foreach ($a as $v) {
if (is_array($v)) return true;
}
return false;
}

function is_multi3($a) {
$c = count($a);
for ($i=0;$i<$c;$i++) {
if (is_array($a[$i])) return true;
}
return false;
}
$iters = 500000;
$time = microtime(true);
for ($i = 0; $i < $iters; $i++) {
is_multi($a);
is_multi($b);
is_multi($c);
}
$end = microtime(true);
echo "is_multi took ".($end-$time)." seconds in $iters times\n";

$time = microtime(true);
for ($i = 0; $i < $iters; $i++) {
is_multi2($a);
is_multi2($b);
is_multi2($c);
}
$end = microtime(true);
echo "is_multi2 took ".($end-$time)." seconds in $iters times\n";
$time = microtime(true);
for ($i = 0; $i < $iters; $i++) {
is_multi3($a);
is_multi3($b);
is_multi3($c);
}
$end = microtime(true);
echo "is_multi3 took ".($end-$time)." seconds in $iters times\n";
?>

$ php multi.php
is_multi took 7.53565130424 seconds in 500000 times
is_multi2 took 4.56964588165 seconds in 500000 times
is_multi3 took 9.01706600189 seconds in 500000 times

Implicit looping, but we can't shortcircuit as soon as a match is found...

$ more multi.php
<?php

$a = array(1 => 'a',2 => 'b',3 => array(1,2,3));
$b = array(1 => 'a',2 => 'b');

function is_multi($a) {
$rv = array_filter($a,'is_array');
if(count($rv)>0) return true;
return false;
}

var_dump(is_multi($a));
var_dump(is_multi($b));
?>

$ php multi.php
bool(true)
bool(false)


Related Topics



Leave a reply



Submit