简体   繁体   English

有没有办法找出 PHP 数组的“深度”?

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

A PHP array can have arrays for its elements. PHP 数组的元素可以有数组。 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?有没有办法找出 PHP 数组中存在的最大嵌套? 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.一个例子是一个函数,如果初始数组没有数组作为元素,则返回 1,如果至少一个元素是数组,则返回 2,依此类推。

Here's another alternative that avoids the problem Kent Fredric pointed out.这是避免 Kent Fredric 指出的问题的另一种选择。 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.它赋予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;
}

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.编辑:非常快速地对其进行了测试,并且似乎可以正常工作。

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. Php 可以创建具有对该数组中其他位置的引用的数组,并且可以包含具有同样递归引用的对象,并且在这种情况下,任何纯递归算法都可以被认为是一种危险的幼稚算法,因为它将溢出堆栈深度递归,并且永远不会终止。

( 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对于您的任务,如果您发现您的数组/结构中出现了递归引用,您可能需要在此处查看用户提供的评论: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:你可能需要拿出你关于算法的 CS 书籍并找到这些婴儿:

( Sorry for being so brief, but delving into graph theory is a bit more than suited for this format ;) ) (抱歉这么简短,但深入研究图论有点不适合这种格式;))

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;
}

After taking a little bit of inspiration here and after finding this RecursiveIteratorIterator thing in PHP Documentation, I came to this solution.在这里获得一点灵感并在 PHP 文档中找到这个RecursiveIteratorIterator之后,我来到了这个解决方案。

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.适用于 PHP5 和 PHP7,希望这会有所帮助。

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.我还没有在大量不同的数组大小上尝试过这个,但它比 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;
}

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.如果您需要一个强大的解决方案,请查看其他地方,但对于简单的情况,我发现这非常快。

Another (better) modification to the function from Jeremy Ruten: 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, ie it will work for simple multi-dimensional arrays.$childrenkey添加默认值允许该函数适用于没有子元素键的简单数组,即它适用于简单的多维数组。

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.$my_array没有任何特定的键来存储其子元素时。

Here's my slightly modified version of jeremy Ruten's function这是我对 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;
}
}

Things like print array_depth($GLOBALS) won't error due to the recursion, but you may not get the result you expected.print array_depth($GLOBALS)这样的东西不会因为递归而出错,但你可能不会得到你期望的结果。

An old question, yet remain relevant to this date.一个古老的问题,但仍然与这个日期相关。 :) :)

Might as well contribute a minor modification to the answer from Jeremy Ruten.不妨对 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.我添加了第二个名为$childrenkey的参数,因为我将子元素存储在特定键中。

An example of the function call is:函数调用的一个例子是:

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

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;
}

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: 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

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):我认为这将解决递归问题,并且在不依赖其他 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;
}

我认为没有内置任何东西。一个简单的递归函数可以很容易地找到。

// 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

I believe the problem highlighted by Kent Frederic is crucial.我相信 Kent Frederic 强调的问题是至关重要的。 The answer suggested by yjerem and Asim are vulnerable to this problem. yjerem 和 Asim 提出的答案很容易受到这个问题的影响。

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. yjerem 再次建议的缩进方法和 dave1010 对我来说不够稳定,因为它依赖于 print_r 函数表示缩进的空格数。 It might vary with time/server/platform.它可能随时间/服务器/平台而变化。

The approach suggested by JoshN might be correct, but I think mine is faster : 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;
}

Post a message if you undertake any testing comparing the different methods.如果您进行任何比较不同方法的测试,请发布消息。 J Ĵ

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.这是您的 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;
  }

Feel free to improve the code :D!随意改进代码:D!

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;
}
//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;
}

in my solution, I evaluate dimension of ARRAY(), not contents/values:在我的解决方案中,我评估 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);

for me is speed, and low complex对我来说是速度和低复杂度

更快的方法:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM