31

I have a multidimensional array e.g. (this can be many levels deep):

$array = Array ( 
    [21] => Array ( ) 
    [24] => Array ( 
        [22] => Array ( ) 
        [25] => Array ( 
            [26] => Array ( ) 
        ) 
    ) 
) 

I am trying to loop through it to see if a certain key exists:

$keySearch = 22; // key searching for

function findKey($array, $keySearch) {
    foreach ($array as $item){
        if (isset($item[$keySearch]) && false === findKey($item[$keySearch], $item)){
            echo 'yes, it exists';
        }
    }
}

findKey($array, $keySearch);

But it finds nothing. Is there an error in the loop?

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
StudioTime
  • 22,603
  • 38
  • 120
  • 207

8 Answers8

53

array_key_exists() is helpful.

Then something like this:

function multiKeyExists(array $arr, $key) {

    // is in base array?
    if (array_key_exists($key, $arr)) {
        return true;
    }

    // check arrays contained in this array
    foreach ($arr as $element) {
        if (is_array($element)) {
            if (multiKeyExists($element, $key)) {
                return true;
            }
        }

    }

    return false;
}

Working example: http://codepad.org/GU0qG5su

Tim
  • 6,281
  • 3
  • 39
  • 49
46

I played with your code to get it working :

function findKey($array, $keySearch)
{
    foreach ($array as $key => $item) {
        if ($key == $keySearch) {
            echo 'yes, it exists';
            return true;
        } elseif (is_array($item) && findKey($item, $keySearch)) {
            return true;
        }
    }
    return false;
}
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
Alexandre Nucera
  • 2,183
  • 2
  • 21
  • 34
  • 1
    Shouldnt: "if (isset( $array[$key] ) )" be: "if( is_array( $array[$key] ) )"? Obviously the $key is set in $array because the foreach is looping that array. – David Lawrence Jul 05 '15 at 02:28
  • `if (is_array($item)) findKey($item, $keySearch);` - the return value of this call is lost. – VolkerK Sep 28 '15 at 15:45
  • 1
    I've edited to condense the if block. If this was my code, I'd rather rather use a single `if` with `||`. *using parentheses as logic requires. – mickmackusa Jan 13 '18 at 05:19
  • thanks for this...btw, from my testing, it's better to set the === operator for this to work properly. – Steven Yip Jul 23 '21 at 08:35
  • To make it more complete, I would suggest also checking if $item isn't empty. This can avoid some problems down the road. – tibelchior Aug 27 '21 at 13:38
  • @tibelchior `$item` "emptiness" may be irrelevant. If a sought key points to a `0`, `null`, or zero-length string value, then `empty()` would give a false negative. Or do you mean before recursing on `$item`? The `foreach()` will simply not iterate anything if the array is empty. – mickmackusa Oct 13 '22 at 22:36
13

Here is a one line solution:

echo strpos(json_encode($array), $key) > 0 ? "found" : "not found";

This converts the array to a string containing the JSON equivalent, then it uses that string as the haystack argument of the strpos() function and it uses $key as the needle argument ($key is the value to find in the JSON string).

It can be helpful to do this to see the converted string: echo json_encode($array);

Be sure to enclose the needle argument in single quotes then double quotes because the name portion of the name/value pair in the JSON string will appear with double quotes around it. For instance, if looking for 22 in the array below then $key = '"22"' will give the correct result of not found in this array:

$array =
Array ( 
        21 => Array ( ), 
        24 => 
        Array ( 
            522 => Array ( ),
            25 =>
                Array ( 
                26 => Array ( ) 
            )
        )
    );

However, if the single quotes are left off, as in $key = "22" then an incorrect result of found will result for the array above.

EDIT: A further improvement would be to search for $key = '"22":'; just incase a value of "22" exists in the array. ie. 27 => "22" In addition, this approach is not bullet proof. An incorrect found could result if any of the array's values contain the string '"22":'

knot22
  • 2,648
  • 5
  • 31
  • 51
  • 2
    I would refuse a solution that works in the simplified case, but not when "special circumstances" occurs. If the values of the array may not contain all arbitrary values cause that might disturb your algorithm, the algorithm is miscrafted – Nico Haase Sep 14 '18 at 06:00
  • Not agreed !! Because it will also return "found" if a value equals the searched key. – Jerry Jun 23 '20 at 17:37
  • 1
    This solution is only correct for the OP's basic, minimal sample data. It is VERY easy for values in the array to cause this technique to give false positive results. I do not endorse this "hacky" solution. This answer makes no attempt to differentiate between "keys" and "values" in the json payload. – mickmackusa Oct 13 '22 at 23:31
5
function findKey($array, $keySearch)
{
    // check if it's even an array
    if (!is_array($array)) return false;

    // key exists
    if (array_key_exists($keySearch, $array)) return true;

    // key isn't in this array, go deeper
    foreach($array as $key => $val)
    {
        // return true if it's found
        if (findKey($val, $keySearch)) return true;
    }

    return false;
}

// test
$array = Array ( 
    21 => Array ( 24 => 'ok' ),
    24 => Array ( 
        22 => Array ( 29 => 'ok' ),
        25 => Array ( 
            26 => Array ( 32 => 'ok' ) 
        )
    )
);

$findKeys = Array(21, 22, 23, 24, 25, 26, 27, 28, 29, 30);
foreach ($findKeys as $key)
{
    echo (findKey($array, $key)) ? 'found ' : 'not found ';
    echo $key.'<br>';
}
minboost
  • 2,555
  • 1
  • 15
  • 15
3

returns false if doesn't exists, returns the first instance if does;

function searchArray( array $array, $search )
{
    while( $array ) {
        if( isset( $array[ $search ] ) ) return $array[ $search ];
            $segment = array_shift( $array );
            if( is_array( $segment ) ) {
                if( $return = searchArray( $segment, $search ) ) return $return;
            }
        }
    }
    return false;
}
Luke Snowden
  • 4,056
  • 2
  • 37
  • 70
2

For sure some errors, is this roughly what you are after? (Untested code):

$keySearch=22; // key seraching for

function findKey($array, $keySearch) 
{ 
    // check whether input is an array
    if(is_array($array)
    {
       foreach ($array as $item)
       {
         if (isset($item[$keySearch]) || findKey($item, $keysearch) === true)
          {
            echo 'yes, it exists';
            return true;
          }
       }
    }
}
Pradeep
  • 9,667
  • 13
  • 27
  • 34
Jelle Ferwerda
  • 1,254
  • 1
  • 7
  • 13
0

Here is one solution that finds and return the value of the key in any dimension array..

function findValByKey($arr , $keySearch){
    $out = null;
    if (is_array($arr)){
        if (array_key_exists($keySearch, $arr)){
            $out = $arr[$keySearch];
        }else{
            foreach ($arr as $key => $value){
                if ($out = self::findValByKey($value, $keySearch)){
                    break;
                }
            }
        }
    }
    return $out;
}
0

I did modified to return value of searched key:

function findKeyInArray($array, $keySearch, &$value)
{
    foreach ($array as $key => $item) {
        if ($key === $keySearch) {
            $value =  $item;
            break;
        } elseif (is_array($item)) {
            findKeyInArray($item, $keySearch,$value);
        }
    }
}
$timeZone = null;
findKeyInArray($request, 'timezone', $timeZone);
  • Welcome to SO! Please take a look at the other answers that were given before. Your approach is mentioned there already. In order to keep the site clear and make it easy to find answers, we try to avoid double answers. – ahuemmer Aug 24 '22 at 06:53