Existe-t-il un moyen de savoir comment & # 8220; profond & # 8221; un tableau de PHP est?

StackOverflow https://stackoverflow.com/questions/262891

  •  06-07-2019
  •  | 
  •  

Question

Un tableau PHP peut avoir des tableaux pour ses éléments. Et ces tableaux peuvent avoir des tableaux et ainsi de suite. Existe-t-il un moyen de connaître l'imbrication maximale existante dans un tableau PHP? Un exemple serait une fonction qui renvoie 1 si le tableau initial ne contient pas de tableaux, 2 si au moins un élément est un tableau, etc.>

Était-ce utile?

La solution

Cela devrait le faire:

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

?>

Éditer: testé très rapidement et il semble fonctionner.

Autres conseils

Voici une autre alternative permettant d’éviter le problème évoqué par Kent Fredric. Il donne à print_r () la tâche de vérifier la récursion infinie (ce qu'il fait bien) et utilise l'indentation dans le résultat. pour trouver la profondeur du tableau.

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

Faites attention aux exemples qui le font de manière récursive.

Php peut créer des tableaux avec des références à d’autres endroits de ce tableau, et peut contenir des objets avec un référencement également récursif, et tout algorithme purement récursif pourrait être considéré dans un tel cas qu'il débordera de la profondeur de la pile récursive et ne se terminera jamais.

(eh bien, il se terminera lorsqu'il dépassera la profondeur de la pile et, à ce stade, votre programme se terminera fatalement, pas ce que je pense que vous voulez.)

Dans le passé, j'ai essayé de sérialiser - > remplacement des repères de référence par des chaînes - > désérialiser pour mes besoins (débogage fréquent, souvent, avec des charges de références récursives) qui semble fonctionner correctement, vous obtenez des trous partout, mais cela fonctionne pour cette tâche.

Pour votre tâche, si vous trouvez que votre tableau / structure contient des références récursives, jetez un coup d'œil aux commentaires de l'utilisateur ayant contribué ici: http://php.net/manual/fr/language.references.spot.php

et ensuite trouver le moyen de compter la profondeur d’un chemin récursif.

Vous devrez peut-être sortir vos livres CS sur les algorithmes et frapper ces bébés:

(Désolé d'être aussi bref, mais la théorie des graphes est un peu plus adaptée à ce format;))

Bonjour, c’est une solution alternative.

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

Après avoir pris un peu d'inspiration ici et après avoir trouvé ceci, RecursiveIteratorIterator dans la documentation PHP, je suis arrivé à cette solution.

Vous devriez utiliser celui-ci, très soigné:

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

Fonctionne à la fois sur PHP5 et PHP7, espérons que cela vous aidera.

Je venais de mettre au point une réponse à cette question lorsque j'ai remarqué ce post. Voici ma solution. Je n'ai pas essayé cette solution sur une tonne de tailles de tableau différentes, mais la réponse était plus rapide que la réponse de 2008 pour les données sur lesquelles je travaillais avec une profondeur d'environ 30 morceaux & 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;
}

Avertissement : cela ne gère pas les cas . Si vous avez besoin d’une solution robuste, cherchez ailleurs, mais pour le cas simple, j’ai trouvé que cela était assez rapide.

Une autre (meilleure) modification de la fonction de 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;
}

L'ajout de une valeur par défaut à $ childrenkey permet à la fonction de fonctionner pour un tableau simple sans clé pour les éléments enfants, autrement dit, elle fonctionnera pour des tableaux multidimensionnels simples.

Cette fonction peut maintenant être appelée à l'aide de:

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

ou

$my_array_depth = array_depth($my_array);

lorsque $ my_array ne possède pas de clé spécifique pour le stockage de ses éléments enfants.

Voici ma version légèrement modifiée de la fonction de 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;
}
}

Des choses comme print array_depth ($ GLOBALS) ne commettront pas d'erreur en raison de la récursion, mais vous risquez de ne pas obtenir le résultat escompté.

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

La fonction proposée par Josh était définitivement plus rapide:

$ 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

Une vieille question, mais qui reste pertinente à cette date. :)

Peut également apporter une modification mineure à la réponse de 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;
}

J'ai ajouté un deuxième paramètre appelé $ childrenkey car je stockais les éléments enfants dans une clé spécifique.

Voici un exemple d'appel de fonction:

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

Je ne pense pas qu'il y ait quoi que ce soit intégré. Une simple fonction récursive pourrait facilement le découvrir.

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

Je pense que le problème mis en évidence par Kent Frederic est crucial. La réponse suggérée par yjerem et Asim est vulnérable à ce problème.

Les approches par indentation suggérées par yjerem à nouveau et dave1010 ne sont pas assez stables pour moi car elles dépendent du nombre d'espaces représentant une indentation avec la fonction print_r. Cela peut varier avec le temps / serveur / plate-forme.

L’approche suggérée par JoshN pourrait être correcte, mais je pense que la mienne est plus rapide:

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

Envoyez un message si vous effectuez des tests en comparant les différentes méthodes. J

Je pense que vous avez oublié de filtrer "[" et "] ou", "et": "et le type de données de la clé (s) et de la (des) valeur (s) du tableau. Voici une mise à jour de votre tableau array_depth plus un 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;
  }

N'hésitez pas à améliorer le code: D!

Je pense que cela résoudrait le problème de la récursivité et donnerait de la profondeur sans s'appuyer sur d'autres fonctions php telles que serialize ou print_r (ce qui est risqué au mieux et peut conduire à des bugs insolubles):

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

Celui-ci semble bien fonctionner pour moi

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

    return $depth;
}

Je voudrais utiliser le code suivant:

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

Un moyen plus rapide:

max(array_map('count', $array));
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top