Is there a way to find out how "deep" a PHP array is?

PhpArraysAssociative Array

Php Problem Overview


A PHP array can have arrays for its elements. And those arrays can have arrays and so on and so forth. Is there a way to find out the maximum nesting that exists in a PHP array? An example would be a function that returns 1 if the initial array does not have arrays as elements, 2 if at least one element is an array, and so on.

Php Solutions


Solution 1 - Php

Here's another alternative that avoids the problem Kent Fredric pointed out. It gives print_r() the task of checking for infinite recursion (which it does well) and uses the indentation in the output to find the depth of the array.

function array_depth($array) {
	$max_indentation = 1;

	$array_str = print_r($array, true);
	$lines = explode("\n", $array_str);
	
	foreach ($lines as $line) {
		$indentation = (strlen($line) - strlen(ltrim($line))) / 4;
		
		if ($indentation > $max_indentation) {
			$max_indentation = $indentation;
		}
	}
	
	return ceil(($max_indentation - 1) / 2) + 1;
}

Solution 2 - Php

This should do it:

<?php

function array_depth(array $array) {
    $max_depth = 1;

    foreach ($array as $value) {
        if (is_array($value)) {
            $depth = array_depth($value) + 1;

            if ($depth > $max_depth) {
                $max_depth = $depth;
            }
        }
    }

    return $max_depth;
}

?>

Edit: Tested it very quickly and it appears to work.

Solution 3 - Php

Beware of the examples that just do it recursively.

Php can create arrays with references to other places in that array, and can contain objects with likewise recursive referencing, and any purely recursive algorithm could be considered in such a case a DANGEROUSLY naive one, in that it will overflow stack depth recursing, and never terminate.

( well, it will terminate when it exceeds stack depth, and at that point your program will fatally terminate, not what I think you want )

In past, I have tried serialise -> replacing reference markers with strings -> deserialise for my needs, ( Often debugging backtraces with loads of recursive references in them ) which seems to work OK, you get holes everywhere, but it works for that task.

For your task, if you find your array/structure has recursive references cropping up in it, you may want to take a look at the user contributed comments here: http://php.net/manual/en/language.references.spot.php

and then somehow find a way to count the depth of a recursive path.

You may need to get out your CS books on algorithms and hit up these babies:

( Sorry for being so brief, but delving into graph theory is a bit more than suited for this format ;) )

Solution 4 - Php

Hi This is an alternative solution.

/*** IN mixed (any value),OUT (string)maxDepth ***/
/*** Retorna la profundidad maxima de un array ***/
function getArrayMaxDepth($input){
	if( ! canVarLoop($input) ) { return "0"; }
	$arrayiter = new RecursiveArrayIterator($input);
	$iteriter = new RecursiveIteratorIterator($arrayiter);
	foreach ($iteriter as $value) {
			//getDepth() start is 0, I use 0 for not iterable values
			$d = $iteriter->getDepth() + 1;
			$result[] = "$d";
	}
	return max( $result );
}
/*** IN mixed (any value),OUT (bool)true/false, CHECK if can be used by foreach ***/
/*** Revisa si puede ser iterado con foreach ***/
function canVarLoop($input) {
	return (is_array($input) || $input instanceof Traversable) ? true : false;
}

Solution 5 - Php

After taking a little bit of inspiration here and after finding this RecursiveIteratorIterator thing in PHP Documentation, I came to this solution.

You should use this one, pretty neat :

function getArrayDepth($array) {
	$depth = 0;
	$iteIte = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));

	foreach ($iteIte as $ite) {
    	$d = $iteIte->getDepth();
	    $depth = $d > $depth ? $d : $depth;
    }
    
    return $depth;
}

Works on both PHP5 and PHP7, hope this helps.

Solution 6 - Php

I had just worked out an answer to this question when I noticed this post. Here was my solution. I haven't tried this on a ton of different array sizes, but it was faster than the 2008 answer for the data I was working with ~30 pieces depth >4.

function deepness(array $arr){
    $exploded = explode(',', json_encode($arr, JSON_FORCE_OBJECT)."\n\n");
    $longest = 0;
    foreach($exploded as $row){
        $longest = (substr_count($row, ':')>$longest)?
            substr_count($row, ':'):$longest;
    }
    return $longest;
}

Warning: this doesn't handle any edge cases. If you need a robust solution look elsewhere, but for the simple case I found this to be pretty fast.

Solution 7 - Php

Here's my slightly modified version of jeremy Ruten's function

// you never know if a future version of PHP will have this in core
if (!function_exists('array_depth')) {
function array_depth($array) {
	// some functions that usually return an array occasionally return false
	if (!is_array($array)) {
		return 0;
	}
	
    $max_indentation = 1;
	// PHP_EOL in case we're running on Windows
    $lines = explode(PHP_EOL, print_r($array, true));

    foreach ($lines as $line) {
        $indentation = (strlen($line) - strlen(ltrim($line))) / 4;
		$max_indentation = max($max_indentation, $indentation);
    }
    return ceil(($max_indentation - 1) / 2) + 1;
}
}

Things like print array_depth($GLOBALS) won't error due to the recursion, but you may not get the result you expected.

Solution 8 - Php

Another (better) modification to the function from Jeremy Ruten:

function array_depth($array, $childrenkey = "_no_children_")
{
    if (!empty($array[$childrenkey]))
    {
        $array = $array[$childrenkey];
    }

    $max_depth = 1;

    foreach ($array as $value)
    {
        if (is_array($value))
        {
            $depth = array_depth($value, $childrenkey) + 1;

            if ($depth > $max_depth)
            {
                $max_depth = $depth;
            }
        }
    }

    return $max_depth;
}

Adding a default value to $childrenkey allows the function to work for simple array with no keys for child elements, i.e. it will work for simple multi-dimensional arrays.

This function can now be called using:

$my_array_depth = array_depth($my_array, 'the_key_name_storing_child_elements');

or

$my_array_depth = array_depth($my_array);

when $my_array doesn't have any specific key for storing its child elements.

Solution 9 - Php

function createDeepArray(){
	static $depth;
	$depth++;
	$a = array();
	if($depth <= 10000){
		$a[] = createDeepArray();
	}
	return $a;
}
$deepArray = createDeepArray();

function deepness(array $arr){
    $exploded = explode(',', json_encode($arr, JSON_FORCE_OBJECT)."\n\n");
    $longest = 0;
    foreach($exploded as $row){
	$longest = (substr_count($row, ':')>$longest)?
	    substr_count($row, ':'):$longest;
    }
    return $longest;
}

function array_depth($arr)
{
    if (!is_array($arr)) { return 0; }
    $arr = json_encode($arr);

    $varsum = 0; $depth  = 0;
    for ($i=0;$i<strlen($arr);$i++)
    {
	$varsum += intval($arr[$i] == '[') - intval($arr[$i] == ']');
	if ($varsum > $depth) { $depth = $varsum; }
    }

    return $depth;
}

echo 'deepness():', "\n";

$start_time = microtime(TRUE);
$start_memory = memory_get_usage();
var_dump(deepness($deepArray));
$end_time = microtime(TRUE);
$end_memory = memory_get_usage();
echo 'Memory: ', ($end_memory - $start_memory), "\n";
echo 'Time: ', ($end_time - $start_time), "\n";

echo "\n";
echo 'array_depth():', "\n";

$start_time = microtime(TRUE);
$start_memory = memory_get_usage();
var_dump(array_depth($deepArray));
$end_time = microtime(TRUE);
$end_memory = memory_get_usage();
echo 'Memory: ', ($end_memory - $start_memory), "\n";
echo 'Time: ', ($end_time - $start_time), "\n";

The function proposed by Josh was definitely faster:

$ for i in `seq 1 10`; do php test.php; echo '-------------------------';done
deepness():
int(10000)
Memory: 164
Time: 0.0079939365386963

array_depth():
int(10001)
Memory: 0
Time: 0.043087005615234
-------------------------
deepness():
int(10000)
Memory: 164
Time: 0.0076408386230469

array_depth():
int(10001)
Memory: 0
Time: 0.042832851409912
-------------------------
deepness():
int(10000)
Memory: 164
Time: 0.0080249309539795

array_depth():
int(10001)
Memory: 0
Time: 0.042320966720581
-------------------------
deepness():
int(10000)
Memory: 164
Time: 0.0076301097869873

array_depth():
int(10001)
Memory: 0
Time: 0.041887998580933
-------------------------
deepness():
int(10000)
Memory: 164
Time: 0.0079131126403809

array_depth():
int(10001)
Memory: 0
Time: 0.04217004776001
-------------------------
deepness():
int(10000)
Memory: 164
Time: 0.0078539848327637

array_depth():
int(10001)
Memory: 0
Time: 0.04179310798645
-------------------------
deepness():
int(10000)
Memory: 164
Time: 0.0080208778381348

array_depth():
int(10001)
Memory: 0
Time: 0.04272198677063
-------------------------
deepness():
int(10000)
Memory: 164
Time: 0.0077919960021973

array_depth():
int(10001)
Memory: 0
Time: 0.041619062423706
-------------------------
deepness():
int(10000)
Memory: 164
Time: 0.0080950260162354

array_depth():
int(10001)
Memory: 0
Time: 0.042663097381592
-------------------------
deepness():
int(10000)
Memory: 164
Time: 0.0076849460601807

array_depth():
int(10001)
Memory: 0
Time: 0.042278051376343

Solution 10 - Php

An old question, yet remain relevant to this date. :)

Might as well contribute a minor modification to the answer from Jeremy Ruten.

function array_depth($array, $childrenkey)
{
	$max_depth = 1;
	
	if (!empty($array[$childrenkey]))
	{
		foreach ($array[$childrenkey] as $value)
		{
			if (is_array($value))
			{
				$depth = array_depth($value, $childrenkey) + 1;
				
				if ($depth > $max_depth)
				{
					$max_depth = $depth;
				}
			}
		}
	}
	
	return $max_depth;
}

I added a second parameter called $childrenkey because I store the child elements in a specific key.

An example of the function call is:

$my_array_depth = array_depth($my_array, 'the_key_name_storing_child_elements');

Solution 11 - Php

This one seems to work fine for me

<?php
function array_depth(array $array)
{
	$depth = 1;
	foreach ($array as $value) {
		if (is_array($value)) {
			$depth += array_depth($value);
			break;
		}
	}

	return $depth;
}

Solution 12 - Php

I don't think there's anything built in. A simple recursive function could easily find out though.

Solution 13 - Php

// very simple and clean approach        
function array_depth($a) {
          static $depth = 0;
          if(!is_array($a)) {
            return $depth;
          }else{
            $depth++;
            array_map("array_depth", $a);
            return $depth;
          }
        }
print "depth:" . array_depth(array('k9' => 'dog')); // return 1

Solution 14 - Php

I believe the problem highlighted by Kent Frederic is crucial. The answer suggested by yjerem and Asim are vulnerable to this problem.

The approaches by indentation suggested by yjerem again, and dave1010 are not stable enough to me because it relies on the number of spaces that represent an indentation with the print_r function. It might vary with time/server/platform.

The approach suggested by JoshN might be correct, but I think mine is faster :

function array_depth($arr)
{
    if (!is_array($arr)) { return 0; }
    $arr = json_encode($arr);

    $varsum = 0; $depth  = 0;
    for ($i=0;$i<strlen($arr);$i++)
    {
        $varsum += intval($arr[$i] == '[') - intval($arr[$i] == ']');
        if ($varsum > $depth) { $depth = $varsum; }
    }

    return $depth;
}

Post a message if you undertake any testing comparing the different methods. J

Solution 15 - Php

I believe you forgot to filter '[' and ']' or ',' and ':' and the data type of the array's key(s) and value(s). Here's an update of your array_depth plus a bonus array_sort_by_depth.

function array_depth($arr){
if (is_array($arr)) {
	array_walk($arr, 
		function($val, $key) use(&$arr) {
			if ((! is_string($val)) && (! is_array($val))) {
				$val = json_encode($val, JSON_FORCE_OBJECT);
			}

			if (is_string($val)) {
				$arr[$key] = preg_replace('/[:,]+/', '', $val);
			}
		}
	);

	$json_strings = explode(',', json_encode($arr, JSON_FORCE_OBJECT));
	
	$max_depth = 0;
		
	foreach ($json_strings as $json_string){
		var_dump($json_string); echo "<br/>";
		$json_string = preg_replace('/[^:]{1}/', '', $json_string);
		var_dump($json_string); echo "<br/><br/>";
		$depth = strlen($json_string);

		if ($depth > $max_depth) {
			$max_depth = $depth;
		}
	}

            return $max_depth;
    }

    return FALSE;
    }


    function array_sort_by_depth(&$arr_val, $reverse = FALSE) {

  if ( is_array($arr_val)) { 
	$temp_arr = array();
            $result_arr = array();

            foreach ($arr_val as $key => $val) {
            	$temp_arr[$key] = array_depth($val);
            }
            
        if (is_bool($reverse) && $reverse == TRUE) {
            	arsort($temp_arr);
            }
            else {
            	asort($temp_arr);
            }

            foreach ($temp_arr as $key => $val) {
            	$result_arr[$key] = $arr_val[$key];
            }

            $arr_val = $result_arr;
	
	return TRUE;
     }

     return FALSE;
  }

Feel free to improve the code :D!

Solution 16 - Php

I think this would solve the recursion problem, and also give the depth without relying on other php functions like serialize or print_r (which is risky at best and can lead to intractable bugs):

function array_depth(&$array) {
    $max_depth = 1;
    $array['__compute_array_depth_flag_ZXCNADJHHDKAQP'] = 1;

    foreach ($array as $value) {
        if (is_array($value) &&
                    !isset($value['__compute_array_depth_flag_ZXCNADJHHDKAQP']))  {
            $depth = array_depth($value) + 1;

            if ($depth > $max_depth) {
                $max_depth = $depth;
            }
        }
    }
    unset($array['__compute_array_depth_flag_ZXCNADJHHDKAQP']);

    return $max_depth;
}

Solution 17 - Php

I would use the following code:

function maxDepth($array) {
    $iterator = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($array), \RecursiveIteratorIterator::CHILD_FIRST);
    $iterator->rewind();
    $maxDepth = 0;
    foreach ($iterator as $k => $v) {
        $depth = $iterator->getDepth();
        if ($depth > $maxDepth) {
            $maxDepth = $depth;
        }
    }
    return $maxDepth;
}

Solution 18 - Php

//Get the dimension or depth of an array
function array_depth($arr)
{
    if (!is_array($arr)) return 0;
    if (empty($arr))     return 1;
    return max(array_map(__FUNCTION__,$arr))+1;
}

Solution 19 - Php

in my solution, I evaluate dimension of ARRAY(), not contents/values:

function Dim_Ar($A, $i){
	if(!is_array($A))return 0;
	$t[] = 1;
	foreach($A AS $e)if(is_array($e))$t[] = Dim_Ar($e, ++ $i) + 1;
	return max($t);
	}

$Q = ARRAY();																				// dimension one
$Q = ARRAY(1);																			// dimension one
$Q = ARRAY(ARRAY(ARRAY()), ARRAY(1, 1, 1));					// dimension is two
$Q = ARRAY(ARRAY());																// dimension is two
$Q = ARRAY(1, 1, 1, ARRAY(), ARRAY(), ARRAY(1));		// dimension is two
$Q = ARRAY(1, 2, 3, ARRAY(ARRAY(1, 1, 1)));					// dimension is two
$Q = ARRAY(ARRAY(ARRAY()), ARRAY());								// dimension is three
$Q = ARRAY(ARRAY(ARRAY()), ARRAY());								// dimension three
$Q = ARRAY(ARRAY(ARRAY()), ARRAY(ARRAY()));					// dimension is three
$Q = ARRAY('1', '2', '3', ARRAY('Q', 'W'), ARRAY('Q', 'W'), ARRAY('Q', 'W'), ARRAY('Q', 'W'), 'pol, y juan', 'sam, y som', '1', '2', 'OPTIONS1' => ARRAY('1', '2', '9'), 'OOO' => ARRAY('1', '2', '9'), 'OPTIONS3' => ARRAY('1', '2', '9', '1', '2', '9', '1', '2', '9', '1', '2', '9', '1', '2', '9'), '3', ARRAY('Q', 'W'), 'OPTIONS2' => ARRAY('1', '2'));
$Q = ARRAY('1', '2', '3', '', ARRAY('Q, sam', 'W', '', '0'), 'ppppppol, y juan', 'sam, y som', '1', '2', 'OPTIONS1' => ARRAY('1', '2', 'ss, zz'), '3', 'PP' => ARRAY('Q', 'WWW', 'Q', 'BMW'), ARRAY('Q', 'YYWW'), 'OPTIONS2' => ARRAY('1', '2', '9'), ARRAY('1', '2', '3'), '33', '33', '33', ARRAY('1', '2', '3', ARRAY(1, 2)));

echo Dim_Ar($Q, 0);

for me is speed, and low complex

Solution 20 - Php

A quicker way:

max(array_map('count', $array));

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionThomas OwensView Question on Stackoverflow
Solution 1 - PhpPaige RutenView Answer on Stackoverflow
Solution 2 - PhpPaige RutenView Answer on Stackoverflow
Solution 3 - PhpKent FredricView Answer on Stackoverflow
Solution 4 - PhpErick BriseñoView Answer on Stackoverflow
Solution 5 - PhpTwystOView Answer on Stackoverflow
Solution 6 - PhpfncompView Answer on Stackoverflow
Solution 7 - Phpdave1010View Answer on Stackoverflow
Solution 8 - PhpAmir SyafrudinView Answer on Stackoverflow
Solution 9 - PhpshachibistaView Answer on Stackoverflow
Solution 10 - PhpAmir SyafrudinView Answer on Stackoverflow
Solution 11 - PhpLinguistoView Answer on Stackoverflow
Solution 12 - PhpKernelMView Answer on Stackoverflow
Solution 13 - PhpAsimView Answer on Stackoverflow
Solution 14 - PhpJonathan HView Answer on Stackoverflow
Solution 15 - PhpcmosversionView Answer on Stackoverflow
Solution 16 - PhpSasanView Answer on Stackoverflow
Solution 17 - PhptonixView Answer on Stackoverflow
Solution 18 - PhpjspitView Answer on Stackoverflow
Solution 19 - PhpStackoverflowView Answer on Stackoverflow
Solution 20 - PhpPranayaView Answer on Stackoverflow