Nasıl "derin" bulmak için bir yolu var mı

14 Cevap php

Bir PHP dizi unsurları diziler olabilir. Ve bu diziler böylece ve benzeri diziler var ve olabilir. PHP dizide var maksimum yuvalama öğrenmek için bir yolu var mı? Bir örnek bu yüzden en az bir eleman bir dizi ise ilk dizi elemanları, 2 gibi diziler yoksa 1 döndüren bir işlev olabilir ve olacaktır.

14 Cevap

Bu yapmak gerekir:

<?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: çok hızlı bir şekilde test edilmiş ve işe görünür.

İşte Kent Fredric işaret sorunu engeller başka bir alternatif bulunuyor. (O iyi yapar) sonsuz yineleme için kontrol ve dizinin derinliğini bulmak için çıktı girinti kullanır print_r() görev verir.

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

Beware sadece yinelemeli bunu örnekler.

Php bu dizideki diğer yerlere referanslar diziler oluşturabilirsiniz ve bu taşacaklardır olmasıyla, böyle bir durumda bir DANGEROUSLY naif biri olarak kabul edilebilir aynı şekilde yinelemeli referans ve herhangi tamamen recursive algoritma ile nesneler içerebilir derinlik recursing yığını ve sonlandırmak asla.

(Iyi, ben seni istiyorum değil, ne bu yığın derinliği aştığı zaman sona erecektir, ve bu noktada program ölümcül sonlandırılacak)

Her yerde delik olsun,> benim ihtiyaçları için deserialise, (Genellikle onları özyinelemeli referansları yükleri ile backtraces ayıklama) Tamam iş gibi görünüyor, ama bu görev için çalışıyor -> dizeleri ile referans işaretlerin değiştirilmesi - Geçmişte, ben tefrika denedim .

Eğer dizi / yapı özyinelemeli referanslar o kadar kırpma vardır bulursanız görev için, size kullanıcı bakmak isteyebilirsiniz Yorumları buraya katkıda: http://php.net/manual/en/language.references.spot.php

ve sonra bir şekilde bir özyinelemeli yolun derinliğini saymak için bir yol bulmak.

Sen algorhthms üzerinde CS kitapları almak ve bu bebekleri vurmak gerekebilir:

(Yani kısa olan, ancak grafik teorisi araştırılacağı üzgünüm biraz daha uygundur, bu format için ;) olduğunu)

Ben bu yazıyı fark edince ben sadece bu soruya bir cevap çalışmıştı. İşte benim çözüm oldu. Ben farklı dizi boyutlarda bir ton üzerinde denemedim, ama ben ~ 30 adet derinlik> 4 ile çalışıyordu veri için 2008 cevap daha hızlı oldu.

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

Ben kolay olsa bulabildiğim basit bir özyinelemeli işlevi yerleşik bir şey olduğunu sanmıyorum.

İşte jeremy Ruten fonksiyonu benim biraz değiştirilmiş bir versiyonu bulunuyor

// 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) olmayacak nedeniyle özyineleme hata, ama gibi şeyler size beklenen sonucu alamayabilirsiniz.

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

Josh tarafından önerilen fonksiyon kesinlikle daha hızlı oldu:

$ 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

Eski bir soru, bu tarihte henüz alakalı kalır. :)

De Jeremy Ruten gelen cevap, küçük bir değişiklik katkıda bulunabilir.

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

Ben belirli bir anahtar içinde alt öğeleri saklamak çünkü $childrenkey adında ikinci bir parametre eklendi.

Işlev çağrısının bir örneği aşağıda verilmektedir:

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

Jeremy ruten gelen işlevi için başka bir (daha iyi) modifikasyon:

function array_depth($array, $childrenkey = "_no_children_")
{
    if (!empty($array[$childrenkey]))
    {
        $array = $array[$childrenkey];
    }

    $max_depth = 1;

    fveyaeach ($array as $value)
    {
        if (is_array($value))
        {
            $depth = array_depth($value, $childrenkey) + 1;

            if ($depth > $max_depth)
            {
                $max_depth = $depth;
            }
        }
    }

    return $max_depth;
}

a default value $childrenkey fonksiyonu çocuk elemanları için hiçbir tuşlarıyla basit bir dizi için çalışmaya olanak ekleyerek, yani basit, çok boyutlu diziler için çalışacaktır.

Bu işlev artık kullanılarak çağrılabilir:

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

veya

$my_array_depth = array_depth($my_array);

when $my_array doesn't have any specific key fveya stveyaing its child elements.

I believe the problem highlighted by Kent Frederic is crucial. The answer suggested by yjerem and Asim are vulnerable to this problem.

Girinti yaklaşımlar yine yjerem tarafından önerilen ve print_r fonksiyonu ile bir girinti temsil mekanların sayısına dayanır çünkü dave1010 benim kadar kararlı değildir. O zaman / sunucu / platformu ile değişebilir.

JoshN tarafından önerilen yaklaşım doğru olabilir, ama benim daha hızlı olduğunu düşünüyorum:

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

Post a message if you undertake any testing comparing the different methods. J

Ben filtre unuttum '[' ve ']' inanmak veya ',' ve ':' ve dizinin anahtar (lar) ve değer (ler) veri türü. İşte array_depth artı bonus array_sort_by_depth bir güncelleme bulunuyor.

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: kod geliştirmek için çekinmeyin!

Ben bu özyineleme sorunu çözmek olacağını düşünüyorum ve aynı zamanda (en iyi ve dirençli böcek yol açabilir en riskli olan), tefrika veya print_r gibi diğer php fonksiyonları dayanmadan derinlik vermek:

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

A hızlı yolu:

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

Merhaba Bu alternatif bir çözümdür.

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