Rotate a column

Python 2, 111 110 109 99 98 96 94 bytes

lambda a,n:[l[:n]+(l[n:]and[L[n]for L in a[i:]+a if L[n:]][1]+l[n+1:])for i,l in enumerate(a)]

Try it online!

Takes input as a list of lines and 0-index column, and returns a list of strings.

Column is rotated up 1.

-11 bytes, thanks to Jo King


APL (Dyalog Extended), 9 bytesSBCS

Full program. Prompts stdin for 2D block of text, then k (0-based or 1-based, depending on APL's current setting), then n. Positive n rotate up, negative n rotate down.

The domain consists of either one of the following:

  1. all Unicode characters, except spaces, leaving 1114111 allowed values, which is more than the required 20.

  2. all numbers, except 0, leaving approximately 2129 allowed values, which is more than the required 20.

Since APL requires 2D blocks to be rectangular, the input must be padded with spaces/zeros. This can be done automatically by entering to the left of a list of strings/numerical lists.

⎕⌽@≠@⎕⍢⍉⎕

Try it online! (the apparent spaces are actually non-breaking spaces)

 prompt for text block

⍢⍉ while transposed:

@⎕ apply the following on the input'th row:

  @≠ at elements different from their prototype (space for characters, zero for numbers):

   ⎕⌽ rotate "input" steps left

APL (Dyalog Unicode), 22+ bytesSBCS

This version allows the full character set by using zeros as identifiable fill element.

0~¨⍨↓⍉⎕⌽@(0≠⊢)@⎕⍉↑0,¨⎕

Try it online!

This of course means that zeros are not allowed in numeric arguments. The corresponding program for all numbers would have the three occurrences of 0 replaced by ' ' and thus use space as fill:

' '~¨⍨↓⍉⎕⌽@(' '≠⊢)@⎕⍉↑' ',¨⎕

If we truly want the full ranges of (even a mixture of) both characters and numbers, we could use null as fill:

n~¨⍨↓⍉⎕⌽@(n≠⊢)@⎕⍉↑⎕,¨⍨n←⎕NULL

And finally, if we wanted to include nulls and objects in the input domain, we could define a fill class and use instances of this as fills:

~∘I¨⍨↓⍉⎕⌽@(~⊢∊I←⎕INSTANCES⊢∘C)@⎕⍉↑⎕,¨⍨⎕NEW⎕FIX':Class C' ':EndClass'

Zsh, 94 87 78 74 69 bytes

-7 bytes by changing to an arithmetic ternary, -9 bytes by changing the character in-place (TIL), -4 bytes by inputting the index on stdin and the strings as arguments, -5 bytes by using a string instead of an array to store the rotating characters.

read i
for s;c+=$s[i]
c=$c[-1]$c
for s;s[i]=$c[$[$#s<i?0:++j]]&&<<<$s

Old Old Old Old Try it online!

Here are the keys to making this answer work:

  • $array[0] or $string[0] is always empty
  • $array[n] or $string[n] is empty if n is larger than the length of the array/string
  • array[i]=c or string[i]=c will replace the element/character.
  • In $[$#s<i?0:++j], j is not incremented if $#s<i.

In the original 94 byte answer, there was an interesting issue I came across involving using <<< to print. I had to use echo to get around it:

for s;echo $s[0,i-1]$c[$[$#s<i?0:++j]]${s:$i}

The reason for this can be seen here:

echo $ZSH_SUBSHELL   # prints 0
<<< $ZSH_SUBSHELL    # prints 1

Here-strings are run in subshells because they are given as stdin to another program. If there is no program given, it is implicitly given to cat. You can see this with <<< $_. <<< $ZSH_SUBSHELL is similar to echo $ZSH_SUBSHELL | cat. Since we need to increment j, we can't be in a subshell.