Есть ли способ узнать, как «глубокий» массив PHP?

Массив PHP может иметь массивы для своих элементов. И эти массивы могут иметь массивы и т. Д. И т. Д. Есть ли способ узнать максимальное гнездование, существующее в массиве PHP? Примером может служить функция, которая возвращает 1, если исходный массив не имеет массивов в качестве элементов, 2, если хотя бы один элемент является массивом и т. Д.

Related of "Есть ли способ узнать, как «глубокий» массив PHP?"

Это должно сделать это:

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

Редактировать: Протестировано очень быстро и, похоже, работает.

Вот еще одна альтернатива, которая позволяет избежать проблемы, о которой указал Кент Фредрик. Он дает 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 может создавать массивы со ссылками на другие места в этом массиве и может содержать объекты с аналогичной рекурсивной ссылкой, и любой чисто рекурсивный алгоритм можно рассматривать в таком случае ОПАСНО наивно, поскольку он будет переполнять глубину стека, и никогда прекратить.

(ну, он будет прерван, когда он превысит глубину стека, и в этот момент ваша программа будет смертельно разорвана, а не то, что я думаю, вы хотите)

В прошлом я пробовал сериализацию -> заменяя ссылочные маркеры на строки -> десериализацию для моих нужд (часто отлаживая обратные трассировки с множеством рекурсивных ссылок в них), которые, похоже, работают нормально, вы получаете дыры везде, но это работает для этой задачи ,

Для вашей задачи, если вы обнаружите, что ваш массив / структура имеет рекурсивные ссылки, возникающие в нем, вы можете взглянуть на комментарии, внесенные пользователем: http://php.net/manual/en/language.references.spot .php

а затем каким-то образом найти способ подсчета глубины рекурсивного пути.

Возможно, вам нужно будет вытащить свои книги CS по алгоритмам и поразить этих детей:

  • Wiki: Глубина ограниченного поиска
  • Wiki: поиск по глубине

(Извините за то, что так краток, но вникание в теорию графов немного больше подходит для этого формата;))

Привет Это альтернативное решение.

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

Я только что ответил на этот вопрос, когда заметил этот пост. Вот мое решение. Я не пробовал это на тоннах разных размеров массива, но он был быстрее, чем ответ 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; } 

Предупреждение : это не обрабатывает случаи кросс. Если вам нужно надежное решение искать в другом месте, но для простого случая я нашел, что это довольно быстро.

Другая (лучшая) модификация функции от Джереми Рутена:

 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 не имеет специального ключа для хранения своих дочерних элементов.

Получив немного вдохновения здесь и после обнаружения этой вещи RecursiveIteratorIterator в документации PHP, я пришел к этому решению.

Вы должны использовать этот, довольно аккуратный:

 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, надеюсь, что это поможет.

Вот моя слегка измененная версия функции 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) , не будут ошибки из-за рекурсии, но вы не можете получить ожидаемый результат.

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

Функция, предложенная Джошем, была определенно быстрее:

 $ 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 

Старый вопрос, но все же остается актуальным для этой даты. 🙂

Могло бы также внести незначительные изменения в ответ от Джереми Рутена.

 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'); 

Я не думаю, что там что-то встроено. Простую рекурсивную функцию можно легко узнать.

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

Я считаю, что проблема, отмеченная Кентом Фредериком, имеет решающее значение. Ответ, предложенный 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; } 

Опубликуйте сообщение, если вы проведете любое тестирование, сравнивающее различные методы. J

Я считаю, что вы забыли фильтровать '[' и ']' или ',' и ':' и тип данных ключей (ов) массива и значений. Вот обновление вашего массива_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 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; } 

Кажется, это работает отлично для меня

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

Быстрее:

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

Мы можем сделать json-кодирование массива, а затем подсчитать максимальное количество открытых скобок массива одновременно.

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

Примечание. Это не будет работать, если в вашем массиве есть объекты.