PHP 数组的元素可以有数组。这些数组可以有数组等等。有没有办法找出 PHP 数组中存在的最大嵌套?一个例子是一个函数,如果初始数组没有数组作为元素,则返回 1,如果至少一个元素是数组,则返回 2,依此类推。
20 回答
这是避免 Kent Fredric 指出的问题的另一种选择。它赋予print_r()检查无限递归的任务(它做得很好)并使用输出中的缩进来查找数组的深度。
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;
}
这应该这样做:
<?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;
}
?>
编辑:非常快速地对其进行了测试,并且似乎可以正常工作。
请注意仅以递归方式执行的示例。
Php 可以创建具有对该数组中其他位置的引用的数组,并且可以包含具有同样递归引用的对象,并且在这种情况下,任何纯递归算法都可以被认为是一种危险的幼稚算法,因为它会溢出堆栈深度递归,并且永远不会终止。
(好吧,当它超过堆栈深度时它将终止,此时您的程序将致命地终止,而不是我认为您想要的)
过去,我尝试过序列化 -> 用字符串替换引用标记 -> 根据我的需要反序列化,(通常调试带有大量递归引用的回溯),这似乎工作正常,你到处都有漏洞,但它适用于该任务.
对于您的任务,如果您发现您的数组/结构中出现了递归引用,您可能需要在此处查看用户提供的评论:http: //php.net/manual/en/language.references.spot .php
然后以某种方式找到一种方法来计算递归路径的深度。
你可能需要拿出你关于算法的 CS 书籍并找到这些婴儿:
(抱歉这么简短,但深入研究图论有点不适合这种格式;))
嗨,这是另一种解决方案。
/*** 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;
}
在这里获得一点灵感并在 PHP 文档中找到这个RecursiveIteratorIterator之后,我来到了这个解决方案。
你应该使用这个,非常整洁:
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,希望这会有所帮助。
当我注意到这篇文章时,我刚刚找到了这个问题的答案。这是我的解决方案。我还没有在大量不同的数组大小上尝试过这个,但它比 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;
}
警告:这不处理任何边缘情况。如果您需要一个强大的解决方案,请查看其他地方,但对于简单的情况,我发现这非常快。
这是我对 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)
不会由于递归而出错,但您可能无法获得预期的结果。
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添加一个默认值允许该函数适用于没有子元素键的简单数组,即它适用于简单的多维数组。
现在可以使用以下方法调用此函数:
$my_array_depth = array_depth($my_array, 'the_key_name_storing_child_elements');
或者
$my_array_depth = array_depth($my_array);
当$my_array没有任何特定的键来存储其子元素时。
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 提出的功能肯定更快:
$ 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
一个古老的问题,但仍然与这个日期相关。:)
不妨对 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');
这个对我来说似乎很好用
<?php
function array_depth(array $array)
{
$depth = 1;
foreach ($array as $value) {
if (is_array($value)) {
$depth += array_depth($value);
break;
}
}
return $depth;
}
我认为没有内置任何东西。一个简单的递归函数可以很容易地找到。
// 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
我相信 Kent Frederic 强调的问题是至关重要的。yjerem 和 Asim 提出的答案很容易受到这个问题的影响。
yjerem 再次建议的缩进方法和 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;
}
如果您进行任何比较不同方法的测试,请发布消息。Ĵ
我相信您忘记过滤“[”和“]”或“,”和“:”以及数组键和值的数据类型。这是您的 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!
我认为这将解决递归问题,并且还可以在不依赖其他 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;
}
我会使用以下代码:
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;
}
//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;
}
在我的解决方案中,我评估 ARRAY() 的维度,而不是内容/值:
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);
对我来说是速度和低复杂度
更快的方法:
max(array_map('count', $array));