Output the anti-clockwise inward spiral of a 2D array

From this stackoverflow question

Given a 2D array of size $$\ M \times N \$$, output the values in a anti-clockwise fashion. The output must start from the outside to the inside and the initial point always is going to be $$\(0,0)\$$.

Example Given:

$$\begin{bmatrix} \color{blue}1&\color{red}2&\color{red}3&\color{red}4 \\ \color{red}5&6&7&\color{red}8 \\ \color{red}9&10&11&\color{red}{12} \\ \color{red}{13}&\color{red}{14}&\color{red}{15}&\color{red}{16}\end{bmatrix}$$

The edge values in counterclockwise is then $$\ 1,5,9,13,14,15,16,12,8,4,3,2 \$$.

Now we repeat the process for the inner values. This will end up with a matrix like the following

$$\begin{bmatrix} \color{blue}6&\color{red}7 \\ \color{red}{10}&\color{red}{11} \end{bmatrix}$$

And the inner values is then $$\ 6,10,11,7 \$$

The final result will be then $$\ 1,5,9,13,14,15,16,12,8,4,3,2,6,10,11,7 \$$

Rules

• Assume non-empty input
• Assume matrix values as positive integers
• Standard I/O Methods apply
• Standard rules and winning criteria apply

Some test cases

Input
[
[1, 2, 3, 4, 5, 6, 7],
[8, 9, 10,11,12,13,14],
[15,16,17,18,19,20,21]
]
Output
1,8,15,16,17,18,19,20,21,14,7,6,5,4,3,2,9,10,11,12,13

--------------------------------------------------------

Input
[
[1,2,3],
[3,2,1],
[4,5,6],
[6,5,4],
[7,8,9],
[9,8,7]
]
Output
1,3,4,6,7,9,8,7,9,4,6,1,3,2,2,5,5,8

-----------------------------------------------------
Input
[
[1]
]
Output
1
-----------------------------------
Input
[
[1, 2],
[2, 1]
]
Output
1,2,1,2
-----------------------------------------------------
Input
[
[1,2,3,6,7],
[2,4,3,2,1],
[3,2,4,5,6],
[6,5,6,5,4],
[10,4,7,8,9],
[12,4,9,8,7]
]
Output
1,2,3,6,10,12,4,9,8,7,9,4,6,1,7,6,3,2,4,2,5,4,7,8,5,5,2,3,4,6

• So are we going clockwise or counterclockwise? – LegionMammal978 Oct 11 '18 at 18:27
• @LegionMammal978 counterclockwise (I though it was called anti-clockwise) – Luis felipe De jesus Munoz Oct 11 '18 at 18:28
• Anti- and counter-clockwise are both correct, with each more common in BrEng and AmEng, respectively. If you really want to confuse, you could use widdershins as well. – Digital Trauma Oct 11 '18 at 19:43

R, 54 bytes

Several bytes saved by @Giuseppe and @J.Doe.

f=function(m)if(ncol(m))c(m[,1],f(t(m[nrow(m):1,-1])))


Try it online!

Recursively strip off the first column and row-reverse/transpose (making the bottom row the new first column) the rest of the matrix until you end up with only one column. Ungolfed "traditional" version:

f <- function(m) {
if(ncol(m) == 1) {
m
} else {
c(m[,1], f(t(m[nrow(m):1,-1])))
}
}


It was pointed out that ncol(m) could be golfed to sum(m) to save another byte because we are allowed to assume positive integer matrix values. But I'll leave it like this since it works for all matrices (even matrices of strings!)

• wow! I love how the use of t() prevents the drop=TRUE default for [ from screwing up the if condition! – Giuseppe Oct 11 '18 at 19:10
• and full disclosure, I had about a 200 byte solution that didn't even work, so kudos to ya! I'll probably get around to awarding you a bounty for this once the question is eligible for a bounty. – Giuseppe Oct 11 '18 at 19:12
• @Giuseppe back to 59 bytes! I was pleasantly surprised by t() to not have to use an is.null test that was in my original attempts. – ngm Oct 11 '18 at 19:41
• Isn't that last m going to be null anyway, so you can change the if-statement for 54 bytes. Seems to work for the test cases. – J.Doe Oct 11 '18 at 20:42

Python 2, 52 bytes

f=lambda a:a and zip(*a)[0]+f(zip(*a[::-1])[1:])or()


Try it online!

Pyth, 9 bytes

shMM.utC_


Try it here!

How?

shMM.utC_     Full program. Takes a 2D array (matrix) from STDIN.
.u        Until a result that has occurred before is found, loop and collect...
_     Reverse the matrix (reverse the order of its rows).
C      Transpose.
t       Remove first element.
hMM          For each element in the resulting 3D array, get the heads of its elements.
s             Flatten.

• Thats cool. As a Pyth beginner I now know I have a lot to learn, – ElPedro Oct 11 '18 at 22:53

Stax, 7 bytes

ôQÖG·í<


Run and debug it

It takes an array of rows on one line, and produces newline-separated output.

Unpacked, ungolfed, and commented, it looks like this.

W       repeat the rest of the program until cancelled explicitly
rM    rotate matrix *clock-wise* (yes, this is the opposite of the challenge)
|c    assert matrix is truthy. (has rows) cancel otherwise.
B     remove the top row of the matrix, and push separately to main stack
rm    reverse the top row (this fixes the rotation direction), and print each value


Run this one

Pyth, 20 bytes

J.TQWJ=+YhJ=J_.TtJ)Y


Try it here

Explanation

J.TQWJ=+YhJ=J_.TtJ)Y
J.TQ                    Call the transposed input J.
WJ            )     While J is not empty...
=+YhJ             ... put the top row into Y (initially [])...
=J   tJ      ... remove the top row...
_.T        ... reverse and transpose (rotate clockwise).
Y    Output the result.


oK, 12 bytes

*+,/(1_+|:)\


Try it online!

This abuses the fact that oK doesn't seem to care too much about shape for transposition. In k this would be 13 bytes: *:',/(1_+|:)\.

       +|:   /reverse, then transpose (rotate right)
1_      /remove first line
(     )\ /fixpoint of the above, keeping intermediate results (scan)
,/         /concatenate all the rows
*+           /get the first element of each row


Clean, 69 bytes

import StdEnv,StdLib
? =transpose
@[h:t]=h++ @(reverse(?t))
@_=[]

@o?


Try it online!

Moves the next row/column to the head of the list so it can pattern matched in the argument.

For the first example in the challenge, this looks like:

@o? [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]
@ h=:[1, 5, 9, 13] t=:[[2, 6, 10, 14], [3, 7, 11, 15], [4, 8, 12, 16]]
[1, 5, 9, 13] ++ @ h=:[14, 15, 16] t=:[[10, 11, 12], [6, 7, 8], [2, 3, 4]]
[1, 6, 9, 13, 14, 15, 16] ++ @ h=:[12, 8, 4] t=:[[11, 7, 3], [10, 6, 2]]
[1, 6, 9, 13, 14, 15, 16, 12, 8, 4] ++ @ h=:[3, 2] t=:[[7, 6], [11, 10]]
[1, 6, 9, 13, 14, 15, 16, 12, 8, 4, 3, 2] ++ @ h=:[6, 10] t=:[[7, 11]]
[1, 6, 9, 13, 14, 15, 16, 12, 8, 4, 3, 2, 6, 10] ++ @ h=:[11, 7] t=:[]
[1, 6, 9, 13, 14, 15, 16, 12, 8, 4, 3, 2, 6, 10, 11, 7] ++ @ []


Julia 0.7, 47 bytes

f(m)=[m[:,1];sum(m)<1?[]:f(rotr90(m[:,2:end]))]


Try it online!

Julia has a convenient built-in to rotate the matrix by 90 degrees eliminating the need for transpose-reverse operations.

As you can see from the compiler warnings, it insists that all components of the ternary conditional should be separated by spaces, and in v. 1.0 this has been actually enforced.

Oddly enough, in this situation the shortest way I found to break out of recursion was to use a try-catch block:

Julia 1.0, 50 bytes

f(m)=[m[:,1];try f(rotr90(m[:,2:end]))catch;[]end]


Try it online!

JavaScript (Node.js), 89 bytes

f=a=>a>[]?[...a.map(x=>x[0]),...f(a[0].map((_,i)=>a.map(y=>y[i]).reverse()).slice(1))]:[]


Try it online!

Takes the first column, transpose the remaining one then reverse each row (= rotate the matrix 90 degrees CW), and then repeat until the array has no more entries.

APL (Dyalog), 24 22 bytes

{×≢⍵:⍵[;1],∇⍉⊖0 1↓⍵⋄⍬}


Try it online!

How?

{×≢⍵:⍵[;1],∇⍉⊖0 1↓⍵⋄⍬}
{                    } - a function
×≢⍵:                  - if non-empty:
⍵[;1]             - the left column
,∇⍉⊖0 1↓⍵    - repeat this function without the left column, rotated counter clockwise
⋄⍬  - otherwise, return an empty vector

• An explanation of the operators would be nice. – Arc676 Oct 13 '18 at 10:45
• @Arc676, added! – Zacharý Oct 14 '18 at 15:40

05AB1E, 1311 10 bytes

ΔRøćRˆ}¯˜þ


-2 bytes thanks to @Emigna.

Explanation:

Δ         # Loop until the stack no longer changes:
R        #  Reverse the order of the rows
#   i.e. [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]]
#    → [[13,14,15,16],[9,10,11,12],[5,6,7,8],[1,2,3,4]]
ø       #  Zip, swapping rows and column
#   → [[13,9,5,1],[14,10,6,2],[15,11,7,3],[16,12,8,4]]
#   → [[14,10,6,2],[15,11,7,3],[16,12,8,4]] and [13,9,5,1]
R     #  Reverse this row
#   → [1,5,9,13]
ˆ    #  Pop and push it to the global array
}         # After the loop:
¯        #  Push the global array
#   i.e. [[1,5,9,13],[14,15,16],[12,8,4],[3,2],[6,10],[11],[7],"",""]
˜       #  Flatten it
#   → [1,5,9,13,14,15,16,12,8,4,3,2,6,10,11,7,"",""]
þ      #  Remove all empty string by only leaving all digits
#   → ["1","5","9","13","14","15","16","12","8","4","3","2","6","10","11","7"]
# (and output it implicitly)


Jelly, 9 bytes

ZḊUƊƬḢ€€Ẏ


Try it online!

Charcoal, 25 bytes

≔⮌ＥＡ⮌ιθＷθ«≔Ｅ§θ⁰⮌Ｅθ§μλθＩ⊟θ


Try it online! Link is to verbose version of code. Explanation:

≔⮌ＥＡ⮌ιθ


Rotate the input by 180°. This is for two reasons: a) the last row is the easiest to remove, and b) it's easier to loop if the row is removed at the end of the loop. (I did try reflecting and outputting clockwise but that took an extra byte.)

Ｗθ«


Repeat until the array is empty.

≔Ｅ§θ⁰⮌Ｅθ§μλθ


Rotate the array by 90°.

Ｉ⊟θ


Remove the last row of the array and print the element as strings on separate lines.

Ruby, 65 bytes

->a{x,*a=a.transpose;(w,*a=a.transpose.reverse;x+=w)while a[0];x}


Try it online!

PowerShell, 266 bytes

Yeah.. PowerShell isn't the best for handling matrices. But, the algorithm is basically the same as the above.. Each row is represented as a comma-separated string, and we basically do a rotation and transposition for each layer. I can probably shave more off, but... I am already in my pajamas...

Filter F{$a=$_-replace"],|]|\s",''-split'\['|?{$_-ne''};$b=@();while($a-ne$null){$N=($a[0]-split',').Count-1;$a=0..$N|%{$i=$_;($a|%{($_-split',')[$i]})-join','};if($d){[array]::Reverse($a)}if($N-gt0){$b+=$a[0];$a=$a[1..$N]}else{$b+=$a;$a=$null};$d=$true}$b-join','}


Try it online!