g | x | w | all
Bytes Lang Time Link
077Wolfram Language Mathematica250912T020452Zthecomme
072R250903T191426Zpajonk
008Pyth250903T152933ZCursorCo
041Julia250907T124933ZMarcMush
055Julia250904T013454ZM--
012Japt250904T135337ZShaggy
042Python 3250903T125016ZTed
055PARI/GP250904T020449Zalephalp
008Jelly250903T201445ZJonathan
027Dyalog APL250903T195048ZAaron
069JavaScript ES6250903T133043ZArnauld
052APL+WIN250903T163204ZGraham
021Charcoal250903T142001ZNeil
015Uiua250903T133000Znyxbird
00905AB1E250903T132425ZKevin Cr

Wolfram Language (Mathematica), 80 77 bytes

-3 bytes thanks to att; also see the comments for their major improvement on this score

Flatten@Reap@FixedPoint[({f,r}=Reverse@#~TakeDrop~UpTo@1;Sow@f;Thread@r)&,#]&

Try it online!

Takes input as matrix of one-character strings e.g.

{{"h", "g", "f"}, {"i", "l", "e"}, {"j", "k", "d"}, {"a", "b", "c"}}

Explanation:

Repeatedly reverse & transpose the input matrix (which has the effect of rotating it by 90º). In between the reverse and the transpose, remember and delete the first row. Keep going until the matrix stops changing, at which point output all the remembered rows, flattened into a simple list.

Flatten[                                     (* Delete all inner braces of nested list *)
  Reap[                                      (* Gather all sown results into list *)
    FixedPoint[                              (* Apply this function to this argument repeatedly 
      (                                         until the result stops changing *)
        {first, rest} = TakeDrop[Reverse[#], (* Reverse order of rows of matrix,
                                 UpTo[1]];      then separate matrix into first row and rest *)
        Sow[first];                          (* Sow the first row *)
        Thread[rest]                         (* Transpose and return the rest *)
      )&, #                                  (* # = input argument *)
    ]&
  ]
]

R, 81 75 72 bytes

Edit: -9 bytes thanks to @Giuseppe.

f=\(M,`~`=tail)if(length(M))Reduce(paste0,c(M~1,f(t(M[nrow(M):1,]~-1))))

Attempt This Online!

Returns single string as requested. Returning a vector of characters would be 15 bytes shorter:

R, 66 60 57 bytes

f=\(M,`~`=tail)if(length(M))c(M~1,f(t(M[nrow(M):1,]~-1)))

Attempt This Online!

Pyth, 9 8 bytes

#p.)Q=C_

Try it online!

Explanation

#p.)Q=C_Q    # implicitly add Q
             # implicitly assign Q = eval(input())
#            # loop until error
 p           # print with no trailing newline
  .)Q        # pop the final element of Q, this will error when Q is empty
     =  Q    # assign to Q
      C      # the transpose of
       _Q    # the reverse of Q

Julia, 41 bytes

!M=print.(M[end,:]),!rotr90(M[1:end-1,:])

Attempt This Online!

Prints the result to stdout and ends with an error

Based on M--'s answer

Julia, 65 57 55* bytes

!M=M[:]==[] ? "" : join(M[end,:])*!rotr90(M[1:end-1,:])

Attempt This Online!

* Thanks to MarcMush's comments.

Japt, 12 bytes

Takes input as an array of lines, outputs a string.

@=z)Ê}f@P±Uo

Try it

@=z)Ê}f@P±Uo     :Implicit input of array U
@                :Left function
 =               :  Reassign to U
  z              :    Rotate 90° clockwise
   )             :  End reassignment
    Ê            :  Length
     }           :End function
      f          :Run the right function and then the left until the left returns falsey (0)
       @         :Right function
        P±       :  Append to variable P (initially the empty string)
          Uo     :    Pop the last element from U, mutating it
                 :Implicit output of final result of right function

Python 3, 62 42 bytes

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

Try it online!

Pops the bottom row of the matrix and then rotates it. Repeats until the matrix is empty.

Also see https://stackoverflow.com/a/8421412/10252820

PARI/GP, 55 bytes

f(a)=if(a,concat(a[#a~,],f(Mat(Vecrev(a[^#a~,]~)))),[])

Attempt This Online!

Takes input as a matrix of characters, e.g., ["h","g","f";"i","l","e";"j","k","d";"a","b","c"]

Jelly, 8 bytes

ṖZUƊƬṪ€Ṗ

A monadic Link that accepts a list of lists of characters and yields a list of characters.

Try it online!

How?

ṖZUƊƬṪ€Ṗ - Link: Lines
    Ƭ    - collect, starting with Lines, while distinct under:
   Ɗ     -   last three links as a monad - f(Current):
Ṗ        -     pop the tail off
 Z       -     transpose
  U      -     reverse each row
     Ṫ€  - tail of each
       Ṗ - pop the tail off (remove the trailing zero that came from tailing an empty list)

Dyalog APL, 27 bytes

⍬∘{0=≢⍵:⍺⋄(⍺,,1↑⍵)∇⊖⍉1↓⍵}∘⊖­⁡​‎‎⁡⁠⁢⁣⁢‏⁠‎⁡⁠⁢⁣⁣‏⁠‎⁡⁠⁢⁣⁤‏‏​⁡⁠⁡‌⁢​‎‎⁡⁠⁡‏⁠‎⁡⁠⁢‏⁠‎⁡⁠⁣‏⁠‎⁡⁠⁢⁣⁡‏⁠‏​⁡⁠⁡‌⁣​‎⁠⁠⁠⁠‎⁡⁠⁢⁤‏⁠‎⁡⁠⁣⁡‏⁠‏​⁡⁠⁡‌⁤​‎‎⁡⁠⁢⁢‏⁠‎⁡⁠⁢⁣‏‏​⁡⁠⁡‌⁢⁡​‎‎⁡⁠⁤‏⁠‎⁡⁠⁢⁡‏‏​⁡⁠⁡‌⁢⁢​‎‎⁡⁠⁣⁣‏⁠‎⁡⁠⁣⁤‏⁠‎⁡⁠⁤⁡‏⁠‎⁡⁠⁢⁡⁢‏‏​⁡⁠⁡‌⁢⁣​‎‎⁡⁠⁤⁢‏‏​⁡⁠⁡‌⁢⁤​‎‎⁡⁠⁤⁣‏⁠‎⁡⁠⁤⁤‏⁠‎⁡⁠⁢⁡⁡‏‏​⁡⁠⁡‌⁣⁡​‎‎⁡⁠⁢⁡⁣‏‏​⁡⁠⁡‌⁣⁢​‎‎⁡⁠⁢⁢⁢‏⁠‎⁡⁠⁢⁢⁣‏⁠‎⁡⁠⁢⁢⁤‏‏​⁡⁠⁡‌⁣⁣​‎‎⁡⁠⁢⁡⁤‏⁠‎⁡⁠⁢⁢⁡‏‏​⁡⁠⁡‌­
                         ∘⊖  # ‎⁡Start by flipping over the input matrix over
⍬∘{                     }    # ‎⁢Then call this recursive function, binding empty list as left arg
       :⍺                    # ‎⁣Return the left arg if
     ≢⍵                      # ‎⁤  the tally (count of major cells, i.e. rows)
   0=                        # ‎⁢⁡  is zero (we've run through the whole matrix)
          (⍺,    )           # ‎⁢⁢Accumulate into ⍺
             ,               # ‎⁢⁣  the ravel of
              1↑⍵            # ‎⁢⁤  the first row
                  ∇          # ‎⁣⁡and call this function again
                     1↓⍵     # ‎⁣⁢  with everything but the first row
                   ⊖⍉        # ‎⁣⁣  transposed and flipped
💎

Created with the help of Luminespire.

JavaScript (ES6), 69 bytes

Expects a matrix of characters and returns an array of characters.

f=m=>[...q=m.pop(),...m+m&&f(q.map((_,i)=>m.map(r=>r[i]).reverse()))]

Try it online!

Algorithm

  1. Extract the last row of the matrix and add it to the output
  2. Rotate the matrix 90° clockwise
  3. Repeat until it's empty

algorithm

Commented

f = m =>            // m[] = input matrix
[                   //
  ...q = m.pop(),   // extract the last row of m[] and save it in q[]
  ...m + m &&       // stop if m[] is empty
  f(                // do a recursive call with m[] rotated clockwise:
    q.map((_, i) => //   for each value at index i in q[]:
      m.map(r =>    //     for each row r[] of m[]:
        r[i]        //       pick the element at index i in r[]
      )             //     end of inner map()
      .reverse()    //     reverse the result
    )               //   end of outer map()
  )                 // end of recursive call
]                   //

APL+WIN 52 bytes

Prompts for character matrix

m←⎕⋄r←⍬⋄⍎∊(×/⍴m)⍴⊂'r←r,,(¯1,↑⌽⍴m)↑m⋄m←⌽⍉m←¯1 0↓m⋄'⋄r

Try it online! Thanks to Dyalog Classic

Charcoal, 21 bytes

WS⊞υιW⌈υ«⊟υ≔Eι⮌⭆υ§μλυ

Try it online! Link is to verbose version of code. Takes input as a list of newline-terminated strings. Explanation: Effectively a port of @Arnauld's JavaScript answer.

WS⊞υι

Input the rectangle of text.

W⌈υ«

Repeat until the rectangle is empty.

⊟υ

Remove and output the last line.

≔Eι⮌⭆υ§μλυ

Rotate the rectangle. In the experimental zip branch of Charcoal this would be ≔Z⮌υυ saving 5 bytes.

Uiua, 16 15 bytes

-1 thanks to Kevin Cruijssen!

/◇⊂⍢(⍉:□°⊂⇌|±⧻)

Try it!

⍢(     # repeat:
  ⇌    #   reverse
  □°⊂  #   unjoin head and box it
  ⍉:   #   transpose the tail   
 |±⧻)  #  until zero length
/◇⊂    # conjoin and flatten

05AB1E, 9 bytes

ΔRćˆø}¯˜J

Input as a matrix of characters.

Try it online.

Explanation:

Δ      # Loop until the result no longer changes
       # using the implicit input-matrix in the first iteration
 R     #  Reverse the rows of the matrix
  ć    #  Extract head; push first row and remainder-matrix separatedd
   ˆ   #  Pop and add this first row to the global array
    ø  #  Zip/transpose the remainder-matrix; swapping rows/columns
}¯     # After the changes loop: push the global array
  ˜    # Flatten this list of lists to a single list of characters and trailing ""
   J   # Join everything together to a string
       # (which is output implicitly as result)

Minor note: usually the zip/transpose ø is used in combination with the builtins í (reverse each inner list) or R (reverse the list) for rotating a matrix 90 degrees: øí/ to rotate clockwise and íø/øR to rotate counter-clockwise. In this case, I use this to my advantage for the extract head ć, by reversing a bit earlier than right before the ø.