4

I am solving a larger problem and at one step I need to rotate a 2D array counter-clockwise.

So if I have this matrix:

1 2 3 4
1 2 3 4
3 4 5 6
3 4 5 6

After the rotation it will be:

4 4 6 6
3 3 5 5
2 2 4 4
1 1 3 3

I have found a solution to rotate it clockwise:

<?php    
$a = array(array(1,2,3,4),array(5,6,7,8),array(9,0,1,2),array(3,4,5,6));
$b = array(); //result

while(count($a)>0)
{
    $b[count($a[0])-1][] = array_shift($a[0]);
    if (count($a[0])==0)
    {
         array_shift($a);
    }
}
?>

The thing is that this has to work even when a is uni-dimensional or has only one element.

So, 1 2 3 4 will become:

4
3
2
1

4 Answers 4

13
$b = call_user_func_array(
    'array_map',
    array(-1 => null) + array_map('array_reverse', $a)
);

I'll leave it as an exercise for the reader to figure out how it works.

Sign up to request clarification or add additional context in comments.

4 Comments

I tried to figure out why the array_map with the -1 => null function (or what actually the function is) groups nth elements from each row... ideone.com/ES75XJ Can you please explain that?
@Cristy see the example "Creating an array of arrays" in the manual. Your code essentially calls array_map(null, [2,1], [3,2], [4,3]) which returns [[2,3,4],[1,2,3]].
Interesting method! You can replace array_map('array_reverse', $a) with $a if you want to just rotate it clockwise, too.
@MattFletcher actually, replacing array_map('array_reverse', $a) with $a will rotate clockwise, but also reflect along the y axis. To only rotate CW, replace array_map('array_reverse', $a) with array_reverse($a).
2

Most concisely, transpose the array then reverse the first level. Done.

Code: (Demo)

$a = [[1,2,3,4],[1,2,3,4],[3,4,5,6],[3,4,5,6]];

var_export(array_reverse(array_map(null, ...$a)));

This approach will fail if the input array is a rectangular matrix with only one row. This is due to how array_map() behaves with a null callback.

To stabilize the transposition, use nested loops (Demo)

$result = [];
foreach ($array as $row) {
    foreach ($row as $i => $v) {
        $result[$i][] = $v;
    }
}
var_export(array_reverse($result));

Or (Demo)

$result = [];
foreach ($array as $row) {
    foreach (array_reverse($row) as $i => $v) {
        $result[$i][] = $v;
    }
}
var_export($result);

Comments

0

Here's a solution that does both clockwise and counter-clockwise matrix rotation:

$a = array(array(1,2,3,4),array(5,6,7,8),array(9,0,1,2),array(3,4,5,6));
$b = $a; //result

$clockwise = false;  // toggle for clockwise / counter-clockwise

$rows = count($a);
$columns = ($rows > 0) ? count($a[0]) : 0;

for ($y = 0; $y < $rows; $y++) {
  for ($x = 0; $x < $columns; $x++) {
    $newX = $clockwise ? $y                  : ($rows - 1) - $y;
    $newY = $clockwise ? ($columns - 1) - $x : $x;
    $b[$newX][$newY] = $a[$x][$y];
  }
}

Comments

0

Here is a recursive way:

            $m = array();
            $m[0] = array('a', 'b', 'c');
            $m[1] = array('d', 'e', 'f');
            $m[2] = array('g', 'h', 'i');
            $newMatrix = array();

            function rotateMatrix($m, $i = 0, &$newMatrix)
            {
                foreach ($m as $chunk) {
                    $newChunk[] = $chunk[$i];
                }
                $newMatrix[] = array_reverse($newChunk);
                $i++;

                if ($i < count($m)) {
                    rotateMatrix($m, $i, $newMatrix);
                }
            }

            rotateMatrix($m, 0, $newMatrix);
            echo '<pre>';
            var_dump($newMatrix);
            echo '<pre>';

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.