有没有一种方法可以在不知道多维数组深度的情况下循环遍历它?

15

到目前为止,如果我需要循环遍历一个多维数组,我会为每个维度使用一个foreach循环。

例如对于两个维度:

foreach($array as $key=>$value)
{
    foreach($value as $k2=>$v2)
    {
         echo
    }
}

当我不知道数组的深度时,该怎么办?也就是说深度是可变的。

我所能想到的唯一方法是编写一整个循环嵌套堆栈,并在下一个值不是数组时退出循环。 这似乎有些愚蠢。

有更好的方法吗?

5个回答

33

可以使用递归,这里有一个输出数组中所有元素的示例:

function printAll($a) {
  if (!is_array($a)) {
    echo $a, ' ';
    return;
  }

  foreach($a as $v) {
    printAll($v);
  }
}

$array = array('hello',
               array('world',
                     '!',
                     array('whats'),
                     'up'),
               array('?'));
printAll($array);

递归时,你需要记住的最重要的一点是需要一个基本情况,在这种情况下你不会再深入。

我喜欢在继续函数之前检查基本情况。这是一种常见的惯用法,但不是必须的。你也可以在foreach循环中检查是否应输出或执行递归调用,但我经常发现那种方式更难以维护。

当前输入与基本情况之间的“距离”称为变量,它是一个整数。在每个递归调用中,该变量应严格减少。在上面的示例中,变量是$a的深度。如果你不考虑变量,就可能会遇到无限递归的问题,最终脚本将因堆栈溢出而死亡。在递归函数之前精确记录变量的内容并加以注释是非常常见的做法。


1
不需要了,使用内置的array_walk_recursive()函数即可。PHP在递归方面表现很差。 - Ярослав Рахматуллин
1
array_walk_recursive仅处理叶节点并跳过子数组。它在给定的示例中无法使用。http://php.net/manual/en/function.array-walk-recursive.php - Matt Smith
谢谢你的回答 :) - LukeDS

6
您可以使用以下函数循环遍历多维数组而无需知道其深度。
// recursive function loop through the dimensional array
function loop($array){

    //loop each row of array
    foreach($array as $key => $value)
    {
         //if the value is array, it will do the recursive
         if(is_array($value) ) $array[$key] =  loop($array[$key]);

         if(!is_array($value)) 
         {
            // you can do your algorithm here
            // example: 
             $array[$key] = (string) $value; // cast value to string data type

         }
    }

    return $array;
}

使用以上函数,它将遍历每个多维数组。以下是您可以传递给循环函数的示例数组:

 //array sample to pass to loop() function
 $data = [
  'invoice' => [
      'bill_information' => [
          'price' => 200.00,
          'quantity' => 5
      ],
      'price_per_quantity' => 50.00
  ],
  'user_id' => 20
];

// then you can pass it like this :
$result = loop($data);
var_dump($result);

//it will convert all the value to string for this example purpose

1

你可以使用递归来解决这个问题:

这里是一个例子

$array = array(1 => array(1 => "a", 2 => array(1 => "b", 2 => "c", 3 => array(1 => "final value"))));

//print_r($array);

printAllValues($array);

function printAllValues($arr) {
    if(!is_array($arr)) {
        echo '<br />' . $arr;
        return;
    }
    foreach($arr as $k => $v) {
        printAllValues($v);
    }
}

它将使用递归来循环遍历数组

它将打印如下

a
b
c
final value

0

array_walk_recursive 中编写一个简单的函数,以显示嵌套级别、键和值:

array_walk_recursive($array, function($v, $k) {
                                 static $l = 0;
                                 echo "Level " . $l++ . ": $k => $v\n";
                             });

另一种展示用use和参考获取结果的方法:
array_walk_recursive($array, function($v) use(&$result) {
                                 $result[] = $v;
                             });

1
array_walk_recursive仅处理叶节点并跳过子数组。它在给定的示例中无法使用。http://php.net/manual/en/function.array-walk-recursive.php - Matt Smith

0

根据之前的递归示例,这里提供一个函数,它保留了一个值所在路径键的数组,以防您需要知道如何到达那里:

function recurse($a,$keys=array()) 
    {
        if (!is_array($a)) 
            {
                echo implode("-", $keys)." => $a <br>";
                return;
            }
        foreach($a as $k=>$v) 
            {
                $newkeys = array_merge($keys,array($k));
                recurse($v,$newkeys);
            }
    }


recurse($array);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接