将子数组与多维数组中的公共元素合并

时间:2012-02-13 02:37:44

标签: php multidimensional-array compare

我正在开发一款由PHP驱动的游戏。我有一个系统可以随机生成带有路径的地图。这是一个例子:

http://i1244.photobucket.com/albums/gg579/Xeniar117/Map.png

(我更新了这篇文章没有足够的代表,这个图片可以直接发布到其他人通过使用他们的代表做的页面,抱歉)

地图的每个单元格都有一个分配给它的4位数字符串,表示行程(W,N,E,S)。因此,上图中的单元格11将具有1110的字符串,单元格17将具有1001中的一个。该字符串(也称为NavString)在规则内随机生成,以防止其将玩家从地图上发送出去。

只有1个行进方向的任何单元格都放入$ endcaps(数组)。此外,任何具有3和4个行进方向的单元都被放入$ endcaps,但是随着行进方向(eq,3路交叉口获得3个条目进入$ endcaps)进入$ endcaps的数量最多只有2个方向的单元格没有被添加到,那就是因为他们有1路进入,只有1条不同的出路,所以它是一条直线进出;没有分支向外也没有死角。

我预先循环通过$ endcaps来获取我要记录的路径的每个部分的起点。使用NavString,我跟踪从$ endcaps收集的单元格中的每条路径,直到我到$ endcaps中的另一个单元格(使用in_array($ endcaps)),整个时间记录它传递到$ paths [$ path]的单元格数字] [$步骤]。每个新的$ endcap I $ path ++和$ endcaps之间的每个新单元格I ++ step ++。

以下是$ path从循环中看起来如何看待的示例: [注意:图像中的地图是这个2D阵列的来源]

Array
(
[0] => Array
    (
        [0] => 4
        [1] => 9
        [2] => 14
    )

[1] => Array
    (
        [0] => 6
        [1] => 5
        [2] => 10
        [3] => 11
    )

[2] => Array
    (
        [0] => 6
        [1] => 1
        [2] => 2
        [3] => 7
    )

[3] => Array
    (
        [0] => 6
        [1] => 7
    )

[4] => Array
    (
        [0] => 6
        [1] => 11
    )

[5] => Array
    (
        [0] => 7
        [1] => 6
    )

[6] => Array
    (
        [0] => 7
        [1] => 2
        [2] => 1
        [3] => 6
    )

[7] => Array
    (
        [0] => 7
        [1] => 12
        [2] => 11
    )

[8] => Array
    (
        [0] => 8
        [1] => 13
    )

[9] => Array
    (
        [0] => 11
        [1] => 10
        [2] => 5
        [3] => 6
    )

[10] => Array
    (
        [0] => 11
        [1] => 6
    )

[11] => Array
    (
        [0] => 11
        [1] => 12
        [2] => 7
    )

[12] => Array
    (
        [0] => 13
        [1] => 8
    )

[13] => Array
    (
        [0] => 13
        [1] => 14
    )

[14] => Array
    (
        [0] => 13
        [1] => 18
        [2] => 19
        [3] => 14
    )

[15] => Array
    (
        [0] => 14
        [1] => 13
    )

[16] => Array
    (
        [0] => 14
        [1] => 9
        [2] => 4
    )

[17] => Array
    (
        [0] => 14
        [1] => 19
        [2] => 18
        [3] => 13
    )

[18] => Array
    (
        [0] => 16
        [1] => 17
        [2] => 22
        [3] => 23
    )

[19] => Array
    (
        [0] => 23
        [1] => 22
        [2] => 17
        [3] => 16
    )

)

我想将子数组中的类似值与$ paths中的其他子数组进行比较。如果有1+个匹配,那么我想将两个数组合并在一起并继续寻找具有至少1个共同值的子数组但是我需要允许在比较中添加任何新的添加。

理想情况下,在完成所有操作之后,应该整合到只有3个子阵列的2D阵列。上述示例的所需结果应如下所示:

array (
    array(1,2,5,6,7,10,11,12)
    array(4,9,14,8,13,18,19)
    array(16,17,22,23)
)

以上将是我可以用来确保入口和出口连接并且玩家不会被困的路径的完美表示!

所以我的问题是如何将$ path(在第一个代码块中)精炼到第二个代码块中的数组?请记住,这些映射是随机生成的,因此$ paths可以包含任意数量的子数组,子数组可以包含任意数量的元素,可以是任何单元格数(取决于系统生成路径的方式)

我希望你们有足够的细节来帮助我,上次我问他们怎么做,他们说我太模糊了(经过一些反思,我同意)。如果还不够,那么......


更新到目前为止我尝试了什么

$set=0;
foreach($paths as $loop1key=>$loop1) {
  foreach($paths as $loop2key=>$loop2) {
    if(count(array_intersect($loop1,$loop2)) > 0) {
      $consolidated = array_merge($loop1,$loop2);
      unset($paths[$loop2key],$paths[$loop1key]);
      $loop1 = $consolidated;
    }
  }
  $after[$set]=$consolidated;
  $set++;
}

AND(由@hackerartist提议):

$after = array();
foreach($paths as $numArray) {
  $addedKey = -1;
  foreach ($after as $key=>$conArray) {
    if ($addedKey<0&&count(array_intersect($conArray,$numArray))){
      $a‌​fter[$key]=array_unique(array_merge($after[$key],$numArray));
      $addedKey = $key;
    }
    if ($addedKey>=0 && count(array_intersect($after[$addedKey],$numArray))) {
      $after[$addedKey] = array_unique(array_merge($after[$addedKey],$after[$key]));
      unset($after[$key]);
    }
  }
  ‌​if ($addedKey<0) {
    $after[] = $numArray;
  }
}

<小时/> UPDATE#2 我调整了我的第二次尝试(那里的那个^^^)并且它似乎在99%的时间工作,但它仍然无法将一些路径部分合并到正确的分组中。我的整个源代码如下,其中包含注释的调整。 (根据PHP专家编辑的第141-158行)

<?php
$rows = 5;//Set statically to test, will be random in final version
$cols = 5;//Same as rows, will eventually be a random value
$gridsize = $rows * $cols;

for($r=0;$r<$rows;$r++){//Loop as many times as $rows
    for($c=0;$c<$cols;$c++){//Loop as many times as $cols
        $cell = ($r * $cols) + $c;//Current cell ((Current row * Total Columns) + Current Column)
        if($r == 0 && $c > 0 && $c < ($cols - 1)){//North edge cell
            $west = $cells[$cell - 1][2];
            $east = rand(0,1);
            $south = rand(0,1);
            $string = $west."0".$east.$south;
        } elseif ($r > 0 && $r < ($rows - 1) && $c == 0){//West Edge
            $north = $cells[$cell - $cols][3];
            $east = rand(0,1);
            $south = rand(0,1);
            $string = "0".$north.$east.$south;
        } elseif ($c == ($cols - 1) && $r > 0 && $r < ($rows - 1)){//East Edge
            $west = $cells[$cell - 1][2];
            $north = $cells[$cell - $cols][3];
            $south = rand(0,1);
            $string = $west.$north."0".$south;
        } elseif ($r == ($rows - 1) && $c > 0 && $c < ($cols - 1)){//South Edge
            $west = $cells[$cell - 1][2];
            $north = $cells[$cell - $cols][3];
            $east = rand(0,1);
            $string = $west.$north.$east."0";
        } else {//Either a Corner or Core Cell
            switch($cell){
                case '0'://NW Corner
                    $east = rand(0,1);
                    $south = rand(0,1);
                    $string = "00".$east.$south;
                break;
                case ($cols - 1)://NE Corner
                    $west = $cells[$cell - 1][2];
                    $south = rand(0,1);
                    $string = $west."00".$south;
                break;
                case ($gridsize - $cols)://SW Corner
                    $north = $cells[$cell - $cols][3];
                    $east = rand(0,1);
                    $string = "0".$north.$east."0";
                break;
                case ($gridsize - 1)://SE Corner
                    $west = $cells[$cell - 1][2];
                    $north = $cells[$cell - $cols][3];
                    $string = $west.$north."00";
                break;
                default://Core cell
                    $west = $cells[$cell - 1][2];
                    $north = $cells[$cell - $cols][3];
                    $east = rand(0,1);
                    $south = rand(0,1);
                    $string = $west.$north.$east.$south;
                break;
            }
        }
        for($x=0;$x<4;$x++){
            if($string[$x]==1){
                $totalnav++;
                $dirs[]=$x;
            }
        }
        if($totalnav == 1 || $totalnav > 2){
            $endcaps[$cell]=$dirs;
        }
        unset($totalnav);
        unset($dirs);
        $cells[] = $string;
    }
}


//Determine center
foreach($cells as $cellnum=>$cell){
    $center = $cell[0]+$cell[1]+$cell[2]+$cell[3];
    if($center > 0){$cell .= "10000";}
    else{$cell.="00000";}
    $blocks[]=$cell;
}

//Refine rooms
for($r=0;$r<$rows-1;$r++){
    for($c=0;$c<$cols-1;$c++){
        $nw = ($r * $cols) + $c;//Current Cell Number
        $ne = $nw + 1;
        $sw = $nw + $cols;
        $se = $ne + $cols;
        $loop = 0;
        if($blocks[$nw][2]==1&&$blocks[$nw][3]==1){$loop++;}
        if($blocks[$ne][0]==1&&$blocks[$ne][3]==1){$loop++;}
        if($blocks[$sw][1]==1&&$blocks[$sw][2]==1){$loop++;}
        if($blocks[$se][0]==1&&$blocks[$se][1]==1){$loop++;}

        if($loop == 4){//Loop detected, creating room
            $blocks[$nw][8]=1;
            $blocks[$ne][7]=1;
            $blocks[$sw][6]=1;
            $blocks[$se][5]=1;
            $loop=0;
        }
    }
}

$path=0;
$oppnodes = array(0=>array(2,-1),1=>array(3,($cols*-1)),2=>array(0,1),3=>array(1,$cols));
foreach($endcaps as $cellnumber=>$directions){
    foreach($directions as $direction){
        $step=0;
        $paths[$path][$step++]=$cellnumber;
        $nextcell = $cellnumber + $oppnodes[$direction][1];
        $nextnode = $oppnodes[$direction][0];
        $end=0;
        while($end==0){
            if(!isset($endcaps[$nextcell])){
                //Pass the torch from last to current
                $currentcell = $nextcell;
                $currentnode = $nextnode;

                $nav = substr($cells[$currentcell],0,4);//Grab nav string from current cell.
                $nav[$currentnode]=0;//Disable opposite node from direction last traveled
                for($x=0;$x<4;$x++){
                    if($nav[$x]=="1"){
                        $nextnode = $oppnodes[$x][0];
                        $nextcell = $currentcell + $oppnodes[$x][1];
                    }
                }
                $paths[$path][$step]=$currentcell;
            } else {
                $paths[$path][$step]=$nextcell;
                $end=1;
            }
            $step++;
        }
        $path++;
    }
}

//Problem area start ===================================================
$after = array();
foreach($paths as $arrayOfNumbers) {
    $addedKey = -1;
    foreach($after as $key=>$newArrayOfNumbers){
        if($addedKey < 0 && count(array_intersect($arrayOfNumbers,$newArrayOfNumbers))){
            $after[$key] = array_unique(array_merge($arrayOfNumbers,$newArrayOfNumbers));
            $addedKey = $key;
        } elseif($addedKey >= 0 && count(array_intersect($after[$key],$newArrayOfNumbers))){
            $after[$key] = array_unique(array_merge($after[$key],$newArrayOfNumbers));
            unset($paths[$key]);
        }
    }
    if($addedKey<0){
        $after[] = $arrayOfNumbers;
    }
}
//Problem area end ===================================


echo"<table><tr><td valign=top>Array Representation of Paths In Map<BR><PRE>";print_r($after);echo"</PRE></td><td valign=top>";


echo "<table cellspacing=0 cellpadding=0 border=1>";
for($r=0;$r<$rows;$r++){
    echo "<tr>";
    for($c=0;$c<$cols;$c++){
        $cellnum=($r*$cols)+$c;
        $cell = current($blocks);
        echo "<td>";
        $directions = array("west","north","east","south","center","nwcorner","necorner","swcorner","secorner");
        foreach($directions as $num=>$direction){if($cell[$num]==1){
            $$direction="white";}else{$$direction="black";}}
        echo "<table width=100% border=0 cellspacing=0 cellpadding=0>
                <tr>
                    <td width=15px height=15px bgcolor=$nwcorner></td>
                    <td width=20px height=15px bgcolor=$north></td>
                    <td width=15px height=15px bgcolor=$necorner></td>
                </tr>
                <tr>
                    <td width=15px height=20px bgcolor=$west></td>
                    <td width=20px height=20px bgcolor=$center align=center><font color=blue>$cellnum</font></td>
                    <td width=15px height=20px bgcolor=$east></td>
                </tr>
                <tr>
                    <td width=15px height=15px bgcolor=$swcorner></td>
                    <td width=20px height=15px bgcolor=$south></td>
                    <td width=15px height=15px bgcolor=$secorner></td>
                </tr>
            </table>";
            echo "</td>";
            next($blocks);
        foreach($directions as $direction){unset($$direction);}
    }
    echo "</tr>";
}
echo "</table>";
unset($blocks);
echo "</td></tr></table>";
unset($after);
?>

我不是要求你检查我的整个代码是否关注你,只是问题区域,看看你是否可以找出为什么它经常错过整合。发布整个源代码似乎是允许您查看实际结果的最合理方式。源不需要任何外部源,也不需要特殊的文件名。我只是无法弄清楚为什么它在99%的时间内没有任何问题,但是有1/100的时间它将无法将路径部分合并到正确的组中。我会继续自己研究,但任何建议都会受到赞赏。谢谢!


更新#3 如此接近!

我一直在修改hackerartist在StackOverflow提出的一些代码,通过一些调整,可以在99%的时间内完成我想要的工作。不幸的是,99%是不可接受的。该代码应该将子数组与任何公共元素合并到多维数组中的任何其他子数组,如下所示:

$array = array(
    array(6,5,0,1,6),
    array(6,11),
    array(11,10,15,16,17,12),
    array(11,12),
    array(12,13),
    array(18,19,14),
    array(7,8,3,4)
);

进入这样的数组:

$array = array(
    array(0,1,5,6,11,10,15,16,17,12,13),
    array(18,19,14),
    array(7,8,3,4)
);

这是我用来尝试完成此操作的代码: $ paths将是$ array以上。

for($x=0;$x<count($paths);$x++){//Loop through paths
                $paths = array_values($paths);//Reset keys
                for($y=0;$y<count($paths);$y++){//Loop through again
                    if($x != $y){//If we arent on the same array
                        if(count(array_intersect($paths[$x],$paths[$y]))){//If there is even 1 matching element
                            $paths[$x] = array_unique(array_merge($paths[$x],$paths[$y]));//Merge arrays
                            unset($paths[$y]);//Remove array just merged
                        }
                    }

                }
            }

还有hackerartist提出的解决方案的调整版本:

$ paths2将是一个像$ array上面的数组

foreach($paths2 as $arrayOfNumbers) {
                $addedKey = -1;
                foreach($after as $key=>$newArrayOfNumbers){
                    if($addedKey < 0 && count(array_intersect($arrayOfNumbers,$newArrayOfNumbers))){
                        $after[$key] = array_unique(array_merge($arrayOfNumbers,$newArrayOfNumbers));
                        $addedKey = $key;
                    } elseif($addedKey >= 0 && count(array_intersect($after[$key],$newArrayOfNumbers))){
                        $after[$key] = array_unique(array_merge($after[$key],$newArrayOfNumbers));
                        unset($paths2[$key]);
                    }
                }
                if($addedKey<0){
                    $after[] = $arrayOfNumbers;
                }
            }

现在,它们可能适用于我提供的示例,但是当您使用我生成的系统生成数组时,这些代码应该可以使用,就像我说的那样,它们会错过一个或两个应该合并到的数组另一个有100个共1个共同元素(估计!!!)我通过代码传递每个子数组中不同元素的不同数组。

任何人都知道我做错了什么以及如何纠正这个漏洞?

1 个答案:

答案 0 :(得分:0)

它可能不是最优雅的解决方案,但它100%的时间都在工作。很简单,我通过精炼代码运行两次,第二次使用第一次输出,然后第二次将其返回到函数之外。重新调用嵌入在函数本身中(所以我猜这意味着它是一个递归函数吗?)无论如何,这里是一个不会一直向下精炼的数组的例子(它错过了合并):

$array= Array
(
    [0] => Array(
            [0] => 1,
            [1] => 0,
            [2] => 5,
            [3] => 6,
            [4] => 11),
   [3] => Array(
            [0] => 10,
            [1] => 11),
    [4] => Array(
            [0] => 11,
            [1] => 12),
    [5] => Array(
            [0] => 12,
            [1] => 17),
    [6] => Array(
            [0] => 15,
            [1] => 16)
    [7] => Array(
            [0] => 17,
            [1] => 18,
            [2] => 23,
            [3] => 22),
    [8] => Array(
            [0] => 17,
            [1] => 22),
    [9] => Array(
            [0] => 21,
            [1] => 22));

运行一次产生了这个:

$array = Array(
    [0] => Array(
            [0] => 21,
            [1] => 22,
            [2] => 17,
            [4] => 18,
            [5] => 23,
            [6] => 12,
            [7] => 11,
            [8] => 10,
            [9] => 1,
            [10] => 0,
            [11] => 5,
            [12] => 6),

    [1] => Array(
            [0] => 7,
            [1] => 12,
            [2] => 2,
            [3] => 3,
            [4] => 4,
            [5] => 9,
            [6] => 8),

    [2] => Array(
            [0] => 15,
            [1] => 16));

这是不对的,因为$ array [0] [6]和$ array [1] [1]都是12,它们所在的数组应该合并,但它们没有。我不确定为什么它没有得到它,但我认为一个简单的解决方案是再次运行它,这是有效的。继续完成功能:

function linkSegments($paths=array(),$ranthru=1){
               if(is_empty($paths)){
                 echo "No segments to link!";die;
               } else {
            for($x=0;$x<count($paths);$x++){//Loop through paths
                $paths = array_values($paths);//Reset keys
                for($y=0;$y<count($paths);$y++){//Loop through again
                    if($x != $y){//If we arent on the same array
                        if(count(array_intersect($paths[$x],$paths[$y]))){//If there is even 1 matching element
                            $paths[$x] = array_unique(array_merge($paths[$x],$paths[$y]));//Merge arrays
                            unset($paths[$y]);//Remove array just merged
                        }
                    }

                }
            }
            if($ranthru == 1){
                $paths = linkSegments($paths,$ranthru=2);
                return $paths;//Set path data to class
            } else {
                return $paths;
            }
               }
        }

调用$ refineArray = linkSegments($ array)[使用第一个代码块中的$ array]将产生正确的结果:

$array = Array(
    [0] => Array(
            [0] => 21,
            [1] => 22,
            [2] => 17,
            [4] => 18,
            [5] => 23,
            [6] => 12,
            [7] => 11,
            [8] => 10,
            [9] => 1,
            [10] => 0,
            [11] => 5,
            [12] => 6,
            [13] => 7,
            [14] => 8,
            [15] => 9,
            [16] => 2,
            [17] => 3,
            [18] => 4),

    [1] => Array(
            [0] => 15,
            [1] => 16));

如果您知道更有效的方法,请告诉我!它是一款游戏,所以我能做得越快越好:D

相关问题