PHP递归foreach意外行为
更新: 我找出了导致无限循环的原因,并进行了检查,以确保每个节点只在路径中包含一次。现在,它返回一个具有预期值的多级数组。关于如何在单个级别阵列中实现这一切,有什么想法吗PHP递归foreach意外行为,php,recursion,foreach,Php,Recursion,Foreach,更新: 我找出了导致无限循环的原因,并进行了检查,以确保每个节点只在路径中包含一次。现在,它返回一个具有预期值的多级数组。关于如何在单个级别阵列中实现这一切,有什么想法吗 Array ( [0] => Array ( [0] => 200 [1] => Array ( [0] => Array
Array
(
[0] => Array
(
[0] => 200
[1] => Array
(
[0] => Array
(
[0] => 109
)
[1] => 155
)
[2] => Array
(
[0] => Array
(
[0] => 164
)
[1] => 110
)
)
)
新代码:
function buildPath($nodes,$src,$target,$pathSum,$elements=array(1))
{
$paths=array();
foreach($nodes[$src] as $dest=>$dist)
{
$e=$elements;
$sum=$pathSum+$dist;
if(!in_array($dest,$e))
{
if($dest==$target)
{
$paths[]=$sum;
}
else
{
$e[]=$dest;
$paths[]=buildPath($nodes,$dest,$target,$sum,$e);
}
}
}
return $paths;
}
原创帖子 长期潜伏者,第一次海报。我认为自己在PHP中处于中等水平,我开始研究递归函数。我遇到了一些意想不到的行为,我很困惑
function buildPath($nodes,$src,$target,$pathSum)
{
$paths=array();
foreach($nodes[$src] as $dest=>$dist)
{
$sum=$pathSum+$dist;
if($dest==$target)
{
$paths[]=$sum;
}
elseif($dest!=$target)
{
$paths[]=buildPath($nodes,$dest,$target,$sum);
}
}
return $paths;
}
使用以下命令调用函数时:
$src=1
$target=4
$pathSum=0
$nodes= Array
(
[1] => Array
(
[4] => 200
[2] => 5
[3] => 10
)
[4] => Array
(
[1] => 200
[2] => 150
[3] => 100
)
[2] => Array
(
[1] => 5
[3] => 4
[4] => 150
)
[3] => Array
(
[1] => 10
[2] => 4
[4] => 100
)
)
它运行一个无限循环直到超时。我开始在不同的时间回显变量以尝试和调试。当我打电话时:
function buildPath($nodes,$src,$target,$pathSum)
{
$paths=array();
foreach($nodes[$src] as $dest=>$dist)
{
$sum=$pathSum+$dist;
if($dest==$target)
{
$paths[]=$sum;
echo "$src->$dest, Target=$target, distance=$dist, sum=$sum. | ";
}
elseif($dest!=$target)
{
$paths[]=buildPath($nodes,$dest,$target,$sum);
echo "$src->$dest, elseif clause | ";
}
}
print_r($paths);
return $paths;
}
使用相同的输入,我得到以下输出:
1->4, Target=4, distance=200, sum=200. | 1->4, Target=4, distance=200, sum=210. | 1->4, Target=4, distance=200, sum=220. | 1->4, Target=4, distance=200, sum=230. | 1->4, Target=4, distance=2, sum=240. | 1->4, Target=4, distance=200, sum=250. |
重复执行,直到脚本超时,每次迭代将总和增加10。转储$paths表明它没有向$paths数组追加任何内容,只是将$paths[0]更新为新的总和
我错过了什么?我是不是完全误解了递归应该如何工作?您能从中进行更改和检查吗
elseif($dest!=$target)
{
$paths[]=buildPath($nodes,$dest,$n,$sum);
}
到
elseif($dest只需将$path
放在函数外部,并在函数中用作全局变量,如下所示,您可以对其进行测试:
成功地解决了这个问题:
function buildPath($nodes,$src,$target,$pathSum,$elements=array(1))
{
$paths=array();
foreach($nodes[$src] as $dest=>$dist)
{
$e=$elements;
$sum=$pathSum+$dist;
if(!in_array($dest,$e))
{
if($dest==$target)
{
$paths[]=$sum;
}
else
{
$e[]=$dest;
$paths=array_merge($paths,buildPath($nodes,$dest,$target,$sum,$e));
}
}
}
return $paths;
}
$n
从哪里来?$path[]=buildPath($nodes,$dest,$n,$sum);
这$n是如何神奇地被邀请参加聚会的?对不起,用$target替换$n。我试图澄清代码,在完成所有替换之前一定复制过。我的代码调用$path[]=buildPath($nodest,$target,$sum)预期的输出是什么?和$level
应该与$src
相同,对吗?这不再是无限循环,但不是我想要的。这最初是一个else子句,但在疑难解答时我将其更改为elseif。仍然会看到意外的结果。它只是更新$PATH[0]不用在数组中添加另一个元素。太好了,谢谢!这很有效!因为它有效而且很优雅。我确实设法用另一种方法解决了它,而不是在我的“else”块中使用了$path=array\u merge($path,buildPath($nodest,$target,$sum,$e);
<?php
$src = 1;
$target = 4;
$pathSum = 0;
$nodes = [
1=>[4=>200, 2=>5, 3=>10],
4=>[1=>200, 2=>150, 3=>100],
2=>[1=>5, 3=>4, 4=>150],
3=>[1=>10, 2=>4, 4=>100],
];
$paths = array(); //<== OUTSIDE THE FUNCTION.... AS GLOBAL VARIABLE...
var_dump( buildPath($nodes, $src, $target, $pathSum) );
function buildPath($nodes, $src, $target, $pathSum, $elements=array(1)) {
global $paths;
foreach($nodes[$src] as $dest=>$dist){
$e = $elements;
$sum = $pathSum+$dist;
if(!in_array($dest, $e)) {
if($dest == $target){
$paths[] = $sum;
}else{
// SIMPLY RECURSE & NOT BUILD $path HERE
$e[] = $dest;
buildPath($nodes, $dest, $target, $sum, $e);
}
}
}
return $paths;
}
// THE var_dump ABOVE PRODUCES:::
array (size=5)
0 => int 200
1 => int 109
2 => int 155
3 => int 164
4 => int 110
function buildPath($nodes,$src,$target,$pathSum,$elements=array(1))
{
$paths=array();
foreach($nodes[$src] as $dest=>$dist)
{
$e=$elements;
$sum=$pathSum+$dist;
if(!in_array($dest,$e))
{
if($dest==$target)
{
$paths[]=$sum;
}
else
{
$e[]=$dest;
$paths=array_merge($paths,buildPath($nodes,$dest,$target,$sum,$e));
}
}
}
return $paths;
}