Czy istnieje sposób, aby dowiedzieć się, jak "głęboka" jest tablica PHP?

Tablica PHP może mieć tablice dla swoich elementów. A te tablice mogą mieć tablice i tak dalej i tak dalej. Czy istnieje sposób na ustalenie maksymalnego zagnieżdżenia, które istnieje w tablicy PHP? Przykładem może być funkcja, która zwraca 1, jeśli początkowa tablica nie ma tablic jako elementów, 2, jeśli przynajmniej jeden element jest tablicą, i tak dalej.

Author: giannis christofakis, 2008-11-04

19 answers

To powinno wystarczyć:

<?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: Przetestowałem go bardzo szybko i wydaje się, że działa.

 52
Author: Jeremy Ruten,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-12 13:55:15

Oto inna alternatywa, która pozwala uniknąć problemu, na który zwrócił uwagę Kent Fredric. Daje print_r () zadanie sprawdzania nieskończonej rekurencji (co robi dobrze) i używa wcięcia na wyjściu, aby znaleźć głębokość tablicy.

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;
}
 70
Author: Jeremy Ruten,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-04 21:58:21

Strzeż się przykładów, które robią to rekurencyjnie.

Php może tworzyć tablice z odniesieniami do innych miejsc w tej tablicy, i może zawierać obiekty z podobnie rekurencyjnym odwołaniem, a każdy czysto rekurencyjny algorytm może być uznany w takim przypadku za niebezpiecznie naiwny, ponieważ przepełni rekurencyjnie głębokość stosu i nigdy nie zakończy się.

(cóż, zakończy się, gdy przekroczy głębokość stosu, a w tym momencie twój program będzie śmiertelnie Zakończ, nie to, co myślę, że chcesz)

W przeszłości próbowałem serialize - > Zamiana znaczników referencyjnych na ciągi - > deserialize dla moich potrzeb, ( często debugowanie ścieżek zwrotnych z ładunkiem rekurencyjnych odniesień w nich ) co wydaje się działać OK, masz dziury wszędzie, ale to działa na to zadanie.

Dla Twojego zadania, jeśli zauważysz, że Twoja tablica / struktura ma przycinające się rekurencyjne referencje, możesz rzucić okiem na komentarze dodane przez Użytkownika tutaj: http://php.net/manual/en/language.references.spot.php

A potem jakoś znaleźć sposób, aby policzyć głębokość ścieżki rekurencyjnej.

Być może trzeba będzie wyciągnąć swoje książki CS na algorhthms i poderwać te dzieci:

(Przepraszam, że tak krótko, ale zagłębianie się w teorię grafów jest nieco bardziej niż odpowiednie dla tego formatu;))

 41
Author: Kent Fredric,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-01 10:21:54

Witam to jest alternatywne rozwiązanie.

/*** 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;
}
 8
Author: Erick Briseño,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-26 20:04:04

Po odrobinie inspiracji tutaj i po znalezieniu tego RecursiveIteratorIterator rzecz w dokumentacji PHP, doszedłem do tego rozwiązania.

Powinieneś użyć tego, całkiem zgrabnego:

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

Działa zarówno na PHP5 jak i PHP7, mam nadzieję, że to pomoże.

 6
Author: TwystO,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-21 17:26:59

Właśnie opracowałem odpowiedź na to pytanie, kiedy zauważyłem ten post. Oto moje rozwiązanie. Nie próbowałem tego na tonie różnych rozmiarów macierzy, ale był szybszy niż odpowiedź 2008 dla danych, które pracowałem z ~30 sztuk głębokość >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;
}

Uwaga : to nie obsługuje żadnych przypadków krawędzi. Jeśli potrzebujesz solidnego rozwiązania poszukaj gdzie indziej, ale dla prostego przypadku uznałem, że jest to dość szybkie.

 4
Author: fncomp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-23 18:10:20

Kolejna (lepsza) modyfikacja funkcji od Jeremy ' ego Rutena:

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

Dodanie domyślnej wartości do $childrenkey pozwala funkcji pracować dla prostej tablicy bez kluczy dla elementów potomnych, tzn. będzie działać dla prostych tablic wielowymiarowych.

Tę funkcję można teraz wywołać używając:

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

Lub

$my_array_depth = array_depth($my_array);

Gdy $my_array nie posiada żadnego klucza do przechowywania elementów potomnych.

 3
Author: Amir Syafrudin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-28 11:08:41

Oto moja nieco zmodyfikowana wersja funkcji jeremy ' ego Rutena]}

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

Rzeczy takie jak print array_depth($GLOBALS) nie spowodują błędu z powodu rekurencji, ale możesz nie uzyskać oczekiwanego wyniku.

 2
Author: dave1010,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-13 12:48:33

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

Funkcja zaproponowana przez Josha była zdecydowanie szybsza:

$ 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
 2
Author: shachibista,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-20 10:27:48

Stare pytanie, ale nadal aktualne do tej daty. :)

Równie dobrze mógłby wnieść drobną modyfikację do odpowiedzi Jeremy ' ego Rutena.
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;
}

Dodałem drugi parametr o nazwie $childrenkey ponieważ przechowuję elementy potomne w określonym kluczu.

Przykładem wywołania funkcji jest:

$my_array_depth = array_depth($my_array, 'the_key_name_storing_child_elements');
 2
Author: Amir Syafrudin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-28 08:39:50

Myślę, że nie ma nic wbudowanego. Prosta funkcja rekurencyjna może się jednak łatwo dowiedzieć.

 1
Author: KernelM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-04 18:48:18
// 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
 1
Author: Asim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-09 01:16:16

Uważam, że problem podkreślony przez Kenta Frederica jest kluczowy. Odpowiedź sugerowana przez yjerem i Asima jest podatna na ten problem.

Podejścia przez wcięcia sugerowane przez yjerem i dave1010 nie są dla mnie wystarczająco stabilne, ponieważ opiera się na liczbie spacji, które reprezentują wcięcia z funkcją print_r. Może się różnić w zależności od czasu / serwera / platformy.

Podejście zaproponowane przez Joshna może być poprawne, ale moim zdaniem jest szybsze :

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

Wyślij wiadomość, jeśli podejmiesz testy porównujące różne metody. J

 1
Author: Sheljohn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-11 19:01:12

Myślę, że zapomniałeś filtrować ' ['i'] 'lub', 'I': 'oraz typ danych klucza (- ów) i wartości tablicy. Oto aktualizacja Twojej array_depth plus 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;
  }

Zapraszam do poprawienia kodu :D!

 1
Author: cmosversion,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-07 18:13:21

Myślę, że to rozwiąże problem rekurencji, a także da głębię bez polegania na innych funkcjach php, takich jak serialize lub print_r (co jest w najlepszym razie ryzykowne i może prowadzić do trudnych błędów):

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;
}
 1
Author: Sasan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-01 23:46:33

Ten wydaje się działać dobrze dla mnie

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

    return $depth;
}
 1
Author: Linguisto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-03 21:37:20

Możemy zakodować tablicę JSON, a następnie policzyć maksymalną liczbę otwartych nawiasów w tym samym czasie.

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

Uwaga: to nie zadziała, jeśli masz obiekty w tablicy.

 0
Author: Narek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-08 14:01:35

Użyłbym następującego kodu:

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;
}
 0
Author: tonix,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-14 10:45:13

Szybszy sposób:

max(array_map('count', $array));
 -2
Author: Pranaya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-22 20:57:05