Frage

A PHP-Array kann seine Elemente haben Arrays für. Und diese Arrays kann Arrays und so weiter und so fort. Gibt es eine Möglichkeit, die maximale Verschachtelung, die in einem PHP-Array existiert, um herauszufinden? Ein Beispiel wäre eine Funktion sein, die 1, wenn die anfängliche Array zurückzugibt nicht Arrays als Elemente hat, 2, wenn mindestens ein Element ein Array ist, und so weiter.

War es hilfreich?

Lösung

Das sollte es tun:

<?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:. Getestet es sehr schnell und es scheint zu funktionieren

Andere Tipps

Hier ist eine weitere Alternative, die das Problem Kent Fredric wies darauf hin, vermeidet. Es gibt print_r () die Aufgabe, für eine unendliche Rekursion zu überprüfen (was es tut gut) und verwendet die Vertiefung in der Ausgabe die Tiefe des Arrays zu finden.

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

Achtung: der Beispiele, die es nur rekursiv tun.

Php kann in diesem Array Arrays mit Verweisen auf andere Orte erstellen, und Objekte mit ebenfalls rekursive Referenzierung enthalten kann, und jeder rein rekursiven Algorithmus könnte in einem solchen Fall eine DANGEROUSLY naiv betrachtet werden, in dass es Stack-Tiefe recursing überlaufen, und nie enden.

(na ja, es wird beendet, wenn es Stack-Tiefe überschreitet, und an diesem Punkt wird Ihr Programm tödlich enden, nicht das, was ich glaube, Sie wollen)

In Vergangenheit habe ich serialise versucht -> Referenzmarken mit Streichern ersetzt -> deserialise für meine Bedürfnisse, (oft Backtraces mit vielen rekursiven Referenzen in ihnen Debugging), die gut zu funktionieren scheint, Sie überall Löcher bekommen, aber es funktioniert für diese Aufgabe.

Für Ihre Aufgabe, wenn Sie Ihre Array finden / Struktur in das rekursive Referenzen auftauchende hat, können Sie hier einen Blick auf den Benutzer beigetragen Kommentare nehmen wollen: http://php.net/manual/en/language.references.spot.php

und dann findet irgendwie einen Weg, um die Tiefe eines rekursiven Pfad zu zählen.

Sie müssen Ihre CS Bücher über algorhthms raus und diese Babys treffen auf:

(Es tut sie so kurz sein, aber Eintauchen in Graphentheorie ist ein bisschen mehr als geeignet für dieses Format;))

Hallo Dies ist eine alternative Lösung.

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

Nach einem wenig Inspiration hier nehmen und nach dem Auffinden dieses RecursiveIteratorIterator Sache in PHP Dokumentation, kam ich zu dieser Lösung.

Sie sollten diese benutzen, recht ordentlich:

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

funktioniert sowohl auf PHP5 und PHP7, hoffe, das hilft.

Ich hatte gerade eine Antwort auf diese Frage gearbeitet, als ich diesen Beitrag bemerkt. Hier war meine Lösung. Ich habe nicht versucht auf einer Tonne von verschiedenen Feldgrößen, aber es war schneller als die 2008 Antwort auf die Daten, die ich arbeite mit ~ 30 Stück Tiefe> 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;
}

Warnung : Das ist nicht verarbeitet alle Grenzfälle. Wenn Sie eine robuste Lösung benötigen woanders suchen, aber für den einfachen Fall fand ich das ziemlich schnell sein.

Eine andere (bessere) Modifikation der Funktion von 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;
}

Hinzufügen ein Standardwert $ childrenkey die Funktion erlaubt, ohne Tasten für untergeordnete Elemente für eine einfache Anordnung zu arbeiten, also wird es für einfache multidimensionalen Arrays zu arbeiten.

Diese Funktion kann nun aufgerufen werden:

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

oder

$my_array_depth = array_depth($my_array);

, wenn $ my_array hat keinen spezifischen Schlüssel für die untergeordneten Elemente zu speichern.

Hier ist meine leicht modifizierte Version von jeremy Ruten der Funktion

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

Dinge wie print array_depth($GLOBALS) nicht Fehler aufgrund der Rekursion, aber Sie können das gewünschte Ergebnis nicht zu erwarten, bekommen.

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

Die Funktion von Josh vorgeschlagen war auf jeden Fall schneller:

$ 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

Eine alte Frage, noch bleiben zu diesem Zeitpunkt relevant. :)

Es könnte aber auch dazu beitragen, eine geringfügige Änderung der Antwort von 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;
}

Ich habe einen zweiten Parameter namens $ childrenkey , weil ich speichere die untergeordneten Elemente in einem bestimmten Schlüssel.

Ein Beispiel für den Funktionsaufruf:

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

Ich glaube nicht, dass irgendetwas in gebaut ist. Eine einfache rekursive Funktion leicht obwohl herausfinden kann.

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

Ich glaube, das Problem hervorgehoben von Kent Frederic von entscheidender Bedeutung ist. Die Antwort vorgeschlagen von yjerem und Asim ist anfällig für dieses Problem.

Die Ansätze durch Einrücken von yjerem vorgeschlagen wieder, und dave1010 ist mir nicht stabil genug, weil es auf der Anzahl der Räume beruht, die eine Vertiefung mit der print_r Funktion darstellen. Es könnte mit der Zeit / Server / Plattform variieren.

Der Ansatz von JoshN vorgeschlagen könnte richtig sein, aber ich glaube, ich ist schneller:

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

eine Nachricht schreiben, wenn Sie eine Prüfung durchführen, die verschiedenen Methoden zu vergleichen. J

Ich glaube, Sie haben vergessen, zu filtern ‚[‘ und ‚]‘ oder ‚‘ und ‚:‘ und der Datentyp des Arrays Taste (n) und Wert (e). Hier ist ein Update Ihrer array_depth zuzüglich eines 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;
  }

Fühlen Sie sich frei, den Code zu verbessern: D

Ich denke, das das Rekursion Problem lösen würde, und auch die Tiefe geben, ohne auf anderen PHP-Funktionen wie serialize oder print_r unter Berufung (die bestenfalls riskant ist und zu hartnäckigem Bugs führen kann):

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

Dies scheint mir gut zu funktionieren

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

    return $depth;
}

Ich würde den folgenden 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;
}

Ein schnellerer Weg:

max(array_map('count', $array));
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top