سؤال

يمكن أن تحتوي مصفوفة PHP على مصفوفات لعناصرها.ويمكن أن تحتوي هذه المصفوفات على مصفوفات وما إلى ذلك.هل هناك طريقة لمعرفة الحد الأقصى للتداخل الموجود في مصفوفة PHP؟على سبيل المثال، دالة تُرجع 1 إذا كان المصفوفة الأولية لا تحتوي على مصفوفات كعناصر، و2 إذا كان عنصر واحد على الأقل عبارة عن مصفوفة، وهكذا.

هل كانت مفيدة؟

المحلول

وهذا ينبغي أن نفعل ذلك:

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

ومن ثم العثور بطريقة ما على طريقة لحساب عمق المسار العودي.

قد تحتاج إلى الحصول على كتب علوم الكمبيوتر الخاصة بك حول الخوارزميات وضرب هؤلاء الأطفال:

(آسف على الاختصار، ولكن الخوض في نظرية الرسوم البيانية هو أكثر من مناسب لهذا التنسيق؛))

ومرحبا هذا هو الحل البديل.

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

بعد أخذ القليل من الإلهام هنا وبعد العثور على هذا تكراريIterator الشيء في وثائق 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، ونأمل أن يكون هذا مفيدًا.

وكنت قد عملت للتو إجابة على هذا السؤال عندما لاحظت هذا المنصب. كان هنا بلدي الحل. لم أحاول ذلك على نصف طن من أحجام مجموعة مختلفة، ولكنه كان أسرع من إجابة 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 لا يحتوي على أي مفتاح محدد لتخزين العناصر الفرعية الخاصة به.

وهنا قال لي نسخة معدلة قليلا من وظيفة جيريمي 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 وعاصم عرضة لهذه المشكلة.

والنهج التي كتبها المسافة البادئة التي اقترحتها 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

وأعتقد أنك نسيت لتصفية '[' و ']' أو '،' و':' ونوع بيانات مفتاح مجموعة (ق) وقيمة (ق). وهنا استكمالا ل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;
  }

لا تتردد في تحسين رمز: D

وأعتقد أن هذا من شأنه أن يحل مشكلة العودية، وأيضا إعطاء عمق دون الاعتماد على وظائف فب أخرى مثل تسلسل أو 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;
}

وهذا واحد يبدو للعمل بشكل جيد بالنسبة لي

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

    return $depth;
}

وأود أن استخدام التعليمات البرمجية التالية:

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

وهناك طريقة أسرع:

max(array_map('count', $array));
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top