有没有办法找出如何“深”PHP数组?
一个PHP数组可以有其数组的元素。 那些数组可以有数组等等。 有没有办法找出存在于PHP数组中的最大嵌套? 例如,如果初始数组没有数组作为元素,则返回1;如果至less有一个元素是数组,则返回2;依此类推。
这应该做到这一点:
<?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; } ?>
编辑:testing它很快,它似乎工作。
这是Kent Fredric指出的另一个避免问题的方法。 它给print_r()检查无限recursion(它很好)的任务,并使用输出中的缩进来查找数组的深度。
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; }
谨防只是recursion的例子。
PHP可以创build数组并引用该数组中的其他位置,并且可以包含具有同样recursion引用的对象,在这种情况下,任何纯粹的recursionalgorithm都可以被认为是一个危险天真的algorithm,因为它会溢出堆栈深度recursion,终止。
(好吧,当它超过堆栈深度时它会终止,在那时你的程序将会致命地终止,而不是我想要的)
在过去,我已经尝试了serialise – >用stringreplace引用标记 – >为我的需要反序列化(通常在其中joinrecursion引用的debugging回溯),这似乎工作正常,你可以在任何地方都find漏洞,但是对于这个任务。
对于你的任务,如果你发现你的数组/结构有recursion引用出现在其中,你可能想看看这里的用户贡献的评论: http : //php.net/manual/en/language.references.spot .PHP
然后以某种方式find一种方法来计算recursionpath的深度。
你可能需要拿出你的CS书籍,并打上这些婴儿:
- 维基:深度有限search
- 维基:深度优先search
(对不起,这么简单,但深入研究graphics理论有点不适合这种格式;))
嗨这是一个替代解决scheme。
/*** 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; }
当我注意到这个post的时候,我刚才就解决了这个问题。 这是我的解决scheme。 我还没有尝试过大量不同的数组大小,但是它的速度比2008年的数据快了30倍,深度> 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; }
警告 :这不处理任何边缘情况。 如果你需要一个健壮的解决scheme看看别处,但对于简单的情况下,我发现这是相当快的。
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; }
给$ childrenkey添加一个默认值允许该函数适用于简单的数组,没有子元素的键,也就是说它可以用于简单的multidimensional array。
现在可以使用以下函数调用此函数:
$my_array_depth = array_depth($my_array, 'the_key_name_storing_child_elements');
要么
$my_array_depth = array_depth($my_array);
当$ my_array没有任何特定的键来存储它的子元素。
在采取了一些灵感之后,在PHP文档中find这个RecursiveIteratorIterator的东西后,我来到了这个解决scheme。
你应该使用这个,很整洁:
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; }
适用于PHP5和PHP7,希望这有助于。
这里是我对jeremy Ruten函数的稍微修改版本
// 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; } }
诸如print array_depth($GLOBALS)
之类的东西不会因为recursion而出错,但是可能不会得到预期的结果。
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";
Josh提出的function肯定是快的:
$ 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
一个古老的问题,但仍然与这个date有关。 🙂
也可以对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; }
我添加了第二个参数$ childrenkey,因为我将子元素存储在特定的键中。
函数调用的一个例子是:
$my_array_depth = array_depth($my_array, 'the_key_name_storing_child_elements');
我不认为有什么内置的。一个简单的recursion函数可以很容易地find。
// 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
我相信肯特·弗雷德里克强调的问题是至关重要的。 yjerem和Asimbuild议的答案很容易出现这个问题。
yjerem再次提出了indentation的方法,而dave1010对我来说不够稳定,因为它依赖于表示print_r函数的缩进空间的数量。 它可能会随着时间/服务器/平台而变化。
JoshN提出的方法可能是正确的,但我认为我的速度更快:
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; }
如果您进行任何比较不同方法的testing,请发布消息。 Ĵ
我相信你忘了过滤'['和']'或','和':'以及数组的键和值的数据types。 这里是你的array_depth的更新加上一个额外的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; }
随意改善代码:D!
我认为这样可以解决recursion问题,并且不依赖其他PHP函数(如serialize或print_r)(这样做风险最大,可能会导致棘手的错误)
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; }
这个似乎对我来说工作得很好
<?php function array_depth(array $array) { $depth = 1; foreach ($array as $value) { if (is_array($value)) { $depth += array_depth($value); break; } } return $depth; }
更快的方法:
max(array_map('count', $array));
我们可以对数组进行json编码,然后同时计算数组开放花括号的最大数量。
function max_depth($arr){ // json encode $string = json_encode($arr); // removing string values to avoid braces in strings $string = preg_replace('/\"(.*?)\"/', '""', $string); //Replacing object braces with array braces $string = str_replace(['{', '}'], ['[', ']'], $string); $length = strlen($string); $now = $max = 0; for($i = 0; $i < $length; $i++){ if($string[$i] == '['){ $now++; $max = $max < $now ? $now : $max } if($string[$i] == ']'){ $now--; } } return $max; }
注意:如果您的数组中有对象,这将不起作用。