递归地遍历数组并打印步行路径

时间:2011-09-28 23:01:51

标签: php arrays recursion multidimensional-array

有人可以帮我提供一些关于如何递归地走一个数组的代码或指令,当到达最后一个元素时,打印到它的完整路径?一个简单的回声将起作用,因为我会将代码调整为我正在开发的其他函数。

该函数不需要计算数组维度,因为将传递此参数:

示例:

$depth = 8;

$array[1][3][5][6][9][5][8][9];

当函数到达第8个元素时,它会打印到它的所有路径:

//print path
'1 -> 3 -> 5 -> 6 -> 9 -> 5 -> 8 -> 9'
  • 正如我所说,只有以这种格式打印才有效,因为我会将代码实现到其他功能中。

  • 数组键可以具有相同的值。显然,整个图书馆的同一序列的价值不一样。

更新

以递归方式行走:

$someArray[1][2][3] = 'end';
$someArray[1][2][6] = 'end';
$someArray[1][3][6] = 'end';
$someArray[4][3][7] = 'end';

function listArrayRecursive(&$array_name, $ident = 0){
    if (is_array($array_name)){
        foreach ($array_name as $k => &$v){
            if (is_array($v)){
                for ($i=0; $i < $ident * 10; $i++){ echo "&nbsp;"; }
                echo $k . " : " . "<br>";
                listArrayRecursive($v, $ident + 1);
            }else{
                for ($i=0; $i < $ident * 10; $i++){ echo "&nbsp;"; }
                echo $k . " : " . $v . "<br>";
            }
        }
    }else{
        echo "Variable = " . $array_name;
    }
}

listArrayRecursive($someArray);

将打印:

1 :
      2 :
                3 : end
                6 : end
      3 :
                6 : end
4 :
      3 :
                7 : end

现在,我怎样才能在每次到达结束时打印数组的路径?例如:

1 :
      2 :
                3 : end : path -> 1,2,3
                6 : end : path -> 1,2,6
      3 :
                6 : end : path -> 1,3,6
4 :
      3 :
                7 : end : path -> 4,3,7

编辑代码添加第三个参与记录路径:

$someArray[1][2][3] = 'end';
$someArray[1][2][6] = 'end';
$someArray[1][3][6] = 'end';
$someArray[4][3][7] = 'end';
$someArray[3][2] = 'end';

function listArrayRecursive(&$array_name, $ident = 0, $path = null){
     foreach ($array_name as $k => &$v){
         if (is_array($v)){
            for ($i=0; $i < $ident * 10; $i++){ echo "&nbsp;"; }
            echo $k . " : " . "<br>";
            $path .= $k . ', ';
            listArrayRecursive($v, $ident + 1, $path);
        }else{
             for ($i=0; $i < $ident * 10; $i++){ echo "&nbsp;"; }
             echo $k . " : " . $v . ' - path -> ' . $path . "<br>";
        }
    }
}

listArrayRecursive($someArray);

将打印:

1 :
          2 :
                    3 : end - path -> 1, 2,
                    6 : end - path -> 1, 2,
          3 :
                    6 : end - path -> 1, 2, 3,
4 :
          3 :
                    7 : end - path -> 1, 4, 3,
3 :
          2 : end - path -> 1, 4, 3, 

9 个答案:

答案 0 :(得分:19)

您可以使用RecursiveIteratorIteratordocs)来完成通过数组递归的艰苦工作。

function listArrayRecursive($someArray) {
    $iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($someArray), RecursiveIteratorIterator::SELF_FIRST);
    foreach ($iterator as $k => $v) {
        $indent = str_repeat('&nbsp;', 10 * $iterator->getDepth());
        // Not at end: show key only
        if ($iterator->hasChildren()) {
            echo "$indent$k :<br>";
        // At end: show key, value and path
        } else {
            for ($p = array(), $i = 0, $z = $iterator->getDepth(); $i <= $z; $i++) {
                $p[] = $iterator->getSubIterator($i)->key();
            }
            $path = implode(',', $p);
            echo "$indent$k : $v : path -> $path<br>";
        }
    }
}

答案 1 :(得分:0)

这个例子是给你一个想法,而不是解决实际的任务。

function recursiveSearch($array,$search){
    foreach($array as $key=>$val){
        if($val==$search)return $key;
        $x=recursiveSearch($array[$key],$search);
        if($x)return $key.' -> '.$x;
    }
}

echo recursiveSearch($array,'search');

如果未找到匹配项,则返回null。

答案 2 :(得分:0)

$a= array(1,2,3,4,5,6);
$val = end($a);
print_array($a,$val);
function print_array(&$arr, $val)
{
    if ($val === false)
        return;

    $curr = prev($arr);
    print_array($arr,$curr);
    echo $val;
}

答案 3 :(得分:0)

我刚刚编写了一个使递归循环更容易的函数: 与array_walk_recursive类似,但具有一些额外的功能

public static function walk($array, $callback, $custom = null, $recursive = false, $info = [])
{
    $r = $recursive;
    if (gettype($r) === 'integer') {
        $r--;
    }
    $info['depth'] = empty($info)?1:$info['depth'] + 1;
    $info['count'] = count($array);
    $info['i'] = 1;
    foreach($array as $k => $v) {
        if (is_array($v) && $r > 0) {
            $array[$k] = static::walk($v, $callback, $custom, $r, $info);
        } else {
            $array[$k] = $callback($v, $k, $custom, $info);
        }
        $info['i'] ++;
    }
    return $array;
}

public static function walkable($v, $k, $custom, $info)
{
    if (is_string($v)) {
        return $v." [ custom: {$custom['key']} ] [ level: ".$info['depth'].' | No '.$info['i'].' of '.$info['count']." ]";
    }
    return $v;
}

这样称呼:

   $result = Namespace\ClassName::walk($array, ['Namespace\ClassName', 'walkable'], ['key'=>'value'], true);

将递归设置为false只会评估第一级。

将recursive设置为true将导致它遍历整个数组。

将递归设置为整数将导致它仅遍历该深度。

可以将可移动函数作为匿名函数引用或传递给回调。

(期望:价值,关键,自定义,信息) 返回的值替换当前值。

可以传递自定义数据,并为您提供一些其他信息。

如果您需要其他信息,可以展开walk功能。

答案 4 :(得分:0)

我有类似的问题。这是一个Depth-First Search-ish解决方案(不包括路径深度,直到数组的最后)。评论&#39; if&#39;声明如果您不想包含该值:

$output = array();
retrievePath($someArray, $output);

function retrievePath($someArray, array &$pathKeeper)
{
    if(!is_array($someArray)){ // $someArray == "end"
        $element = array_pop($pathKeeper) ?? '';// if the array is empty pop returns null, we don't want that
        array_push($pathKeeper, $element . '->'. $someArray);
    } else{
        end($someArray);//we want to get the last element from the array so we move the internal pointer to it's end
        $endElKey = key($someArray);//take the key where the pointer is
        reset($someArray);
        foreach($someArray as $key=>$value){
            $element = array_pop($pathKeeper);
            array_push($pathKeeper, $element === null ? $key : $element . '->' . $key);// we don't want '->' at the beginning
            retrievePath($value, $pathKeeper);
            if($key != $endElKey) //we check whether this is not the last loop
                array_push($pathKeeper, $element);
        }
    }
}

答案 5 :(得分:0)

<?php
function printListRecursive($a, $var='', $i = 0) {
    if (!is_array($a)) {
        $var .= $a;
        return $var;
    }
    $string = "";
    foreach ($a as $k => $value) {
        $string .= str_repeat("&nbsp;&nbsp;", $i) .' - '. $k . ':';
        if (!is_array($value)) {
            $string .= $value . '<br />';
        } else {
            $string .= '<br />';
            $string .= printListRecursive($value, $var, $i + 1);
        }
    }
    return $string;
}
$test_array = [
    'America' => [
        'Argentina' => 'Buenos Aires',
        'Peru' => 'Lima'
    ],
    'Europe' => [
        'Ireland' => 'Dublin',
        'France' => 'Paris',
        'Italy' => 'Rome'
    ]
];
$result = printListRecursive($test_array);
echo $result;
?>

Check code here

答案 6 :(得分:0)

我基于@salathe的功能提出了以下功能。它返回一个数组,其中每个元素是一个数组,其中包含索引为0的叶子和索引为1的路径键的数组:

function loosenMultiDimensionalArrayPathForEachVal($array) {
    $iterator = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($array), \RecursiveIteratorIterator::SELF_FIRST);        
    $iterator->rewind();
    $res = [];
    foreach ($iterator as $v) {
        $depth = $iterator->getDepth();
        for ($path = array(), $i = 0, $z = $depth; $i <= $z; $i++) {
            $path[] = $iterator->getSubIterator($i)->key();
        }
        $leaf = $array;
        foreach ($path as $pathKey) {
            $leaf = $leaf[$pathKey];
        }
        if (!is_array($leaf)) {
            $res[] = [
                $v,
                $path
            ];
        }
    }
    return $res;
}

我实现这一目标的主要原因是,如果当前的迭代叶是对象,则$iterator->hasChildren()返回true。因此,我将无法以这种方式获得它的路径。

答案 7 :(得分:0)

我找到了此解决方案,该解决方案还考虑到结构的元素是否为数组:

$file_contents=file_get_contents("data.json");
$json_dump=json_decode($file_contents); 
printPath($json_dump, '', "" ,"");

function printPath($the_array, $path, $prevType) {
// Parse all elements of a structure 
// and print full PHP path to each one.
    foreach($the_array as $key => $value)  {
        if(is_array($value)) {
            // Array element cannot be directly printed: process its items as     objects:
            printPath($value, $path  . $key , "array");
        } else {            
            if (!is_object($value))  { // If the element is not an object, it can be printed (it's a leaf)
                if(is_string($value)) { 
                    $finalValue = '"' . $value . '"'; 
                } else { 
                    $finalValue = $value;
                }
                if($prevType == "array") {
                    // If array element, add index in square brackets
                    echo($path  . "["  . $key . "] =  " .  $finalValue . "<br>");
                } else {
                    echo($path . $key  . " = " . $finalValue . "<br>");                     
                }   

            } else { // else store partial path and iterate:
                if($prevType == "array") {
                    // Path of array element must contain element index:  
                    printPath($value, $path . "["  . $key . "]->"  , "dummy");
                } else {
                    printPath($value, $path . $key . "->", "dummy");
                }           
            }
        }
    }
}

示例输出:

status->connections->DSS-25->band = "X"
status->connections->DSS-25->endAt = "2019-11-20T20:40:00.000Z"
status->connections->DSS-25->startAt = "2019-11-20T12:40:00.000Z"
geometry[0]->obs[0]->name = "UDSC64"
geometry[0]->obs[0]->hayabusa2->azm = 90.34
geometry[0]->obs[0]->hayabusa2->alt = -20.51

如果有人感兴趣,这里是Javascript的端口:

function iterate(obj, stack, prevType) {
    for (var property in obj) {
        if ( Array.isArray(obj[property]) ) {
            //console.log(property , "(L="  + obj[property].length + ") is an array  with parent ", prevType, stack);
            iterate(obj[property], stack  + property , "array");
        } else {
            if ((typeof obj[property] != "string")  && (typeof obj[property] != "number"))  {
                if(prevType == "array") {
                    //console.log(stack + "["  + property + "] is an object, item of " , prevType, stack);
                    iterate(obj[property], stack + "["  +property + "]." , "object");
                } else {
                    //console.log(stack +    property  , "is " , typeof obj[property] , " with parent ", prevType, stack );
                    iterate(obj[property], stack  + property + ".", "object");
                }   
            } else {
                if(prevType == "array") {
                    console.log(stack + "["  + property + "] =  "+  obj[property]);

                } else {
                    console.log(stack +    property  , " =  " ,  obj[property] );                       
                }   
            }
        }
    }
}

iterate(object, '', "File")

答案 8 :(得分:-1)

您可以添加第三个参数,将实际路径保存为String。最后你可以输出它。