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

15

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

Luis felipe De jesus Munoz

Posted 2018-10-11T17:46:22.473

Reputation: 9 639

So are we going clockwise or counterclockwise? – LegionMammal978 – 2018-10-11T18:27:22.950

@LegionMammal978 counterclockwise (I though it was called anti-clockwise) – Luis felipe De jesus Munoz – 2018-10-11T18:28:41.157

7

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 – 2018-10-11T19:43:57.770

Answers

12

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!)

ngm

Posted 2018-10-11T17:46:22.473

Reputation: 3 974

wow! I love how the use of t() prevents the drop=TRUE default for \[`` from screwing up the if condition! – Giuseppe – 2018-10-11T19:10:13.240

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 – 2018-10-11T19:12:00.783

@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 – 2018-10-11T19:41:27.790

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 – 2018-10-11T20:42:19.627

9

Python 2, 52 bytes

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

Try it online!

TFeld

Posted 2018-10-11T17:46:22.473

Reputation: 19 246

7

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.

Mr. Xcoder

Posted 2018-10-11T17:46:22.473

Reputation: 39 774

Thats cool. As a Pyth beginner I now know I have a lot to learn, – ElPedro – 2018-10-11T22:53:55.447

5

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

recursive

Posted 2018-10-11T17:46:22.473

Reputation: 8 616

4

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.

user48543

Posted 2018-10-11T17:46:22.473

Reputation:

4

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

zgrep

Posted 2018-10-11T17:46:22.473

Reputation: 1 291

3

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] ++ @ []

Οurous

Posted 2018-10-11T17:46:22.473

Reputation: 7 916

3

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!

Kirill L.

Posted 2018-10-11T17:46:22.473

Reputation: 6 693

2

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.

Shieru Asakoto

Posted 2018-10-11T17:46:22.473

Reputation: 4 445

2

05AB1E, 13 11 10 bytes

ΔRøćRˆ}¯˜þ

-2 bytes thanks to @Emigna.

Try it online or verify all test cases.

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]]
   ć      #  Head extracted
          #   → [[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)

Kevin Cruijssen

Posted 2018-10-11T17:46:22.473

Reputation: 67 575

2

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

Zacharý

Posted 2018-10-11T17:46:22.473

Reputation: 5 710

An explanation of the operators would be nice. – Arc676 – 2018-10-13T10:45:01.097

1@Arc676, added! – Zacharý – 2018-10-14T15:40:16.913

1

Jelly, 9 bytes

ZḊUƊƬḢ€€Ẏ

Try it online!

Erik the Outgolfer

Posted 2018-10-11T17:46:22.473

Reputation: 38 134

1

Charcoal, 25 bytes

≔⮌EA⮌ιθWθ«≔E§θ⁰⮌Eθ§μλθI⊟θ

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

≔⮌EA⮌ιθ

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.)

Wθ«

Repeat until the array is empty.

≔E§θ⁰⮌Eθ§μλθ

Rotate the array by 90°.

I⊟θ

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

Neil

Posted 2018-10-11T17:46:22.473

Reputation: 95 035

1

Ruby, 65 bytes

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

Try it online!

G B

Posted 2018-10-11T17:46:22.473

Reputation: 11 099

1

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!

Jeff Freeman

Posted 2018-10-11T17:46:22.473

Reputation: 221