20
\$\begingroup\$

Given a non-empty string, keep removing the first and last characters until you get to one or two characters.

For example, if the string was abcde, your program should print:

abcde
 bcd
  c

However, if it was abcdef, it should stop at two characters:

abcdef
 bcde
  cd

Trailing newlines and trailing spaces at the end of each line are optional. You can have as many as you want or none.

Test cases

ABCDEFGHIJKLMNOPQRSTUVWXYZ -> ABCDEFGHIJKLMNOPQRSTUVWXYZ
                               BCDEFGHIJKLMNOPQRSTUVWXY 
                                CDEFGHIJKLMNOPQRSTUVWX  
                                 DEFGHIJKLMNOPQRSTUVW   
                                  EFGHIJKLMNOPQRSTUV    
                                   FGHIJKLMNOPQRSTU     
                                    GHIJKLMNOPQRST      
                                     HIJKLMNOPQRS       
                                      IJKLMNOPQR        
                                       JKLMNOPQ         
                                        KLMNOP          
                                         LMNO           
                                          MN            

ABCDEFGHIJKLMNOPQRSTUVWXYZ! -> ABCDEFGHIJKLMNOPQRSTUVWXYZ!
                                BCDEFGHIJKLMNOPQRSTUVWXYZ 
                                 CDEFGHIJKLMNOPQRSTUVWXY  
                                  DEFGHIJKLMNOPQRSTUVWX   
                                   EFGHIJKLMNOPQRSTUVW    
                                    FGHIJKLMNOPQRSTUV     
                                     GHIJKLMNOPQRSTU      
                                      HIJKLMNOPQRST       
                                       IJKLMNOPQRS        
                                        JKLMNOPQR         
                                         KLMNOPQ          
                                          LMNOP           
                                           MNO            
                                            N             

A -> A

AB -> AB

Remember this is , so the code with the smallest number of bytes wins.

\$\endgroup\$
9
  • \$\begingroup\$ Can the output be a list of strings, instead of printing the strings? \$\endgroup\$ Nov 19, 2016 at 2:24
  • \$\begingroup\$ @GregMartin Yes. \$\endgroup\$
    – Oliver Ni
    Nov 19, 2016 at 2:29
  • 1
    \$\begingroup\$ Do we need to have the leading spaces on each line? \$\endgroup\$ Nov 19, 2016 at 2:29
  • \$\begingroup\$ @ETHproductions Yes. \$\endgroup\$
    – Oliver Ni
    Nov 19, 2016 at 2:35
  • 9
    \$\begingroup\$ @Oliver That's important information, you should include it in the text \$\endgroup\$
    – Luis Mendo
    Nov 19, 2016 at 2:48

27 Answers 27

12
\$\begingroup\$

V, 10 bytes

ò^llYpr $x

Try it online!

Explanation:

ò^ll         " While there are at least two non-whitespace characters on the current line
    Y        " Yank this line
     p       " Paste it below
      r      " Replace the first character with a space
        $    " Move to the end of the line
         x   " Delete a character
\$\endgroup\$
0
9
\$\begingroup\$

ES6 (Javascript), 47, 48, 43 bytes

EDIT: Replaced ternary operator with &&, prefixed padding string with the newline. Thanks @Neil for an excellent advice !

EDIT: included the function name for the recursive invocation, stripped one byte off by using a literal newline

Golfed

R=(s,p=`
 `)=>s&&s+p+R(s.slice(1,-1),p+' ')

Test

R=(s,p=`
 `)=>s&&s+p+R(s.slice(1,-1),p+' ')

console.log(R("ABCDEFGHIJKLMNOPQRSTUVWXYZ"))

ABCDEFGHIJKLMNOPQRSTUVWXYZ
 BCDEFGHIJKLMNOPQRSTUVWXY
  CDEFGHIJKLMNOPQRSTUVWX
   DEFGHIJKLMNOPQRSTUVW
    EFGHIJKLMNOPQRSTUV
     FGHIJKLMNOPQRSTU
      GHIJKLMNOPQRST
       HIJKLMNOPQRS
        IJKLMNOPQR
         JKLMNOPQ
          KLMNOP
           LMNO
            MN

console.log(R("ABCDEFGHIJKLMNOPQRSTUVWXYZ!"))

ABCDEFGHIJKLMNOPQRSTUVWXYZ!
 BCDEFGHIJKLMNOPQRSTUVWXYZ
  CDEFGHIJKLMNOPQRSTUVWXY
   DEFGHIJKLMNOPQRSTUVWX
    EFGHIJKLMNOPQRSTUVW
     FGHIJKLMNOPQRSTUV
      GHIJKLMNOPQRSTU
       HIJKLMNOPQRST
        IJKLMNOPQRS
         JKLMNOPQR
          KLMNOPQ
           LMNOP
            MNO
             N
\$\endgroup\$
2
  • 1
    \$\begingroup\$ I notice that @xnor starts with p equal to a newline and a space; maybe that could help you too. \$\endgroup\$
    – Neil
    Nov 19, 2016 at 13:22
  • 1
    \$\begingroup\$ Oh, and you can also use s&& instead of s?...:''. \$\endgroup\$
    – Neil
    Nov 19, 2016 at 14:15
8
\$\begingroup\$

Python, 45 bytes

f=lambda s,p='\n ':s and s+p+f(s[1:-1],p+' ')

Recursively outputs the string, plus a newline, plus the leading spaces for the next line, plus the recursive result for the shortened string with an extra space in the prefix.

If a leading newline was allowed, we could save a byte:

f=lambda s,p='\n':s and p+s+f(s[1:-1],p+' ')

Compare with a program (49 bytes in Python 2):

s=input();p=''
while s:print p+s;s=s[1:-1];p+=' '
\$\endgroup\$
0
6
\$\begingroup\$

Brainfuck, 67 bytes

>>,[.>,]<[>++++++++++.<[-]<[<]>[-]++++++++[-<++++>]<[<]>[.>]>[.>]<]

This should work on all brainfuck flavors.

Try it online!

Ungolfed code:

# Print and read input_string into memory
>>,[.>,]<
while input_string is not empty [
    # Print newline
    >+++++ +++++.<
    # Remove last character
    [-]
    # GOTO start of input_string
    <[<]>
    # Remove first character
    [-]
    # Add space to space_buffer
    +++++ +++[-<++++>]
    # GOTO start of space_buffer
    <[<]>
    # Print space_buffer
    [.>]
    # Print input_string
    >[.>]
<]

There should still be some bytes to chop off here; I've only recently began using brainfuck, so my pointer movement is probably very inefficient.

\$\endgroup\$
6
\$\begingroup\$

J, 39 19 16 bytes

[:|:]#"0~#\.<.#\

Try it online!

This was a nice example of how a different perspective can allow J to express a problem more naturally. Originally, I was seeing the problem "horizontally", as described in the OP -- a sequence with successive edges being removed:

enter image description here

But you can also view it vertically, as a kind of upside down histogram:

enter image description here

From this perspective, we are just repeating each letter some number of times, an operation J's copy primitive # can accomplish in 1 character.

Consider abcde:

  • #\.<.#\ Determine the number of times to repeat each character, ie, produce the mask 1 2 3 2 1:

    #\  => 1 2 3 4 5
    #\. => 5 4 3 2 1
    ----------------
    <.  => 1 2 3 2 1  NB. elementwise min
    
  • ]#"0~ Use that mask to duplicate the input:

    a  
    bb 
    ccc
    dd 
    e  
    
  • [:|: Transpose:

    abcde
     bcd 
      c
    
\$\endgroup\$
5
\$\begingroup\$

Python 2, 50 bytes

def f(i,j=0):
 print' '*j+i
 if i:f(i[1:-1],j+1)

Simple recursive function that keeps shortening the string until it disappears.

Call as f('string')

Output

string
 trin
  ri
\$\endgroup\$
5
\$\begingroup\$

Perl, 31 bytes

30 bytes of code + -p flag.

s/( *)\S(.+).$/$& 
 $1$2/&&redo

To run it :

perl -pE 's/( *)\S(.+).$/$&
 $1$2/&&redo' <<< "abcdef"

Explanations : The \S and .$ correspond to the first and last character, (.+) the middle and ( *) to the trailing spaces that are added every time we remove one character from the beginning. So the regex removes one character from the beginning, one from the end, and add one leading space each time.

\$\endgroup\$
4
\$\begingroup\$

GNU sed 24 Bytes

Includes +2 for -rn

:
p
s/[^ ](.+)./ \1/
t

Prints, replaces the first non-space character with a space, and deletes the last character until nothing changes.

\$\endgroup\$
1
  • \$\begingroup\$ This is really nice. \$\endgroup\$
    – Jonah
    May 11, 2021 at 19:49
3
\$\begingroup\$

MATL, 9 bytes

tg!*YRPRc

This produces trailing spaces and newlines.

Try it online!

Explanation

t      % Input string implicitly. Duplicate
g!     % Convert to logical and transpose: gives a column vector of ones
*      % Multiply with broadcast. This gives a square matrix with the string's
       % ASCII codes on each row
YR     % Lower triangular part: make elements above the diagonal 0
P      % Flip vertically
R      % Upper triangular part: make elements below the diagonal 0
c      % Convert to char. Implicitly display, with char 0 shown as space
\$\endgroup\$
3
\$\begingroup\$

Batch, 92 bytes

@set/ps=
@set t=
:g
@echo %t%%s%
@set t= %t%
@set s=%s:~1,-1%
@if not "%s%"=="" goto g

Takes input on STDIN.

\$\endgroup\$
3
\$\begingroup\$

C, 73 bytes

f(char*s){char*b=s,*e=s+strlen(s)-1;while(e-b>-1)puts(s),*b++=32,*e--=0;}

Ungolfed:

f(char*s) {
  char *b=s,
       *e=s+strlen(s)-1;
  while (e-b>-1)
    puts(s),
    *b++=32,
    *e--=0;
}

Usage:

main(){
  char a[] = "abcde";
  f(a);
}
\$\endgroup\$
3
\$\begingroup\$

05AB1E, 8 bytes

Code:

ÐvNú,¦¨D

Explanation:

Ð          # Triplicate the input
 v         # Length times do...
  Nú,      # Prepend N spaces and print with a newline
     ¦¨    # Remove the first and the last character
       D   # Duplicate that string

Uses the CP-1252 encoding. Try it online!

\$\endgroup\$
3
\$\begingroup\$

Pyke, 10 bytes

VQlRc
l7tO

Try it here!

\$\endgroup\$
3
\$\begingroup\$

Haskell, 47 43 bytes

f s@(a:b:c)=s:map(' ':)(f.init$b:c)
f s=[s]

Try it on Ideone. Output is a list of strings which was allowed in the comments of the challenge. To print, run with (putStr.unlines.f) instead of just f.

Edit: Saved 4 bytes after noticing that trailing whitespace is allowed.

Prelude> (putStr.unlines.f)"codegolf"
codegolf
 odegol
  dego
   eg
               --(trailing whitespace)
\$\endgroup\$
3
\$\begingroup\$

Perl 6, 42 bytes

for get,{S/\w(.*)./ $0/}.../\s..?$/ {.put}

Expanded:

for

  # generate the sequence
  get,       # get a line from the input

  {          # bare block lambda with implicit parameter 「$_」
             # used to produce the rest of the sequence

    S/       # replace
      \w     # a word character ( to be removed )
      (      # set 「$0」
        .*   # any number of any characters
      )
      .      # any character ( to be removed )
    / $0/    # append a space

  }

  ...        # repeat that until

  /          # match
    \s       # whitespace
    .        # any character
    .?       # optional any character
    $        # end of string
  /

{
  .put       # print $_ with trailing newline
}
\$\endgroup\$
3
\$\begingroup\$

Vyxal C, 4 bytes

‡ḢṪ↔

Try it Online!

i have turned to the dark side

i am now a flag abuser

thanks to lyxal for helping me get to the 4-byte sol (from 8 bytes)

Explanation

   ↔  While results have not reached a fixed point
‡     2-byte function
 Ḣ    a[1:]
  Ṫ   a[:-1]

C     Center the list and join on newlines

The below less cheese program does the same thing. øĊ is the same as the C flag.

Vyxal j, 6 bytes

‡ḢṪ↔øĊ

Try it Online!

Since outputting a list was allowed, using the j flag to join on newlines is reasonable. You can also append to use no flags at all.

\$\endgroup\$
2
  • \$\begingroup\$ I'm proud of you for joining the flag side of vyxal. Very good \$\endgroup\$
    – lyxal
    May 11, 2021 at 5:20
  • \$\begingroup\$ @lyxal i am suffering \$\endgroup\$
    – hyper-neutrino
    May 11, 2021 at 5:22
2
\$\begingroup\$

Jelly, 9 bytes

J’⁶ẋoUµ⁺Y

Try it online!

If the input is of length \$2n\$, this outputs with \$n\$ lines of trailing newlines and spaces

How it works

J’⁶ẋoUµ⁺Y - Main link. Takes a string A on the left
      µ⁺  - Do the following twice:
J         -   Yield [1, 2, 3, ..., 2n]
 ’        -   Decrement; [0, 1, 2, ..., 2n-1]
  ⁶ẋ      -   Repeat a space that many times; [[], [' '], [' ', ' '], ...]
     U    -   Reverse A
    o     -   Logical OR
        Y - Join by newlines

The logical OR command o has the following behaviour:

[[], [5], [6, 7], [8, 9, 10]] o [1, 2, 3, 4] = [[1, 2, 3, 4], [5, 2, 3, 4], [6, 7, 3, 4], [8, 9, 10, 4]]

so only the leftmost characters are replaced by spaces. We do this twice, reversing each time, to get both the left and right side

\$\endgroup\$
2
\$\begingroup\$

Canvas, 9 bytes

[L[jk}]∔\

Try it here!

\$\endgroup\$
1
\$\begingroup\$

Retina, 17 bytes

;{G:`
\S(.+).
 $1

Try it online!

\$\endgroup\$
1
\$\begingroup\$

C++14, 117 bytes

auto f(auto s){decltype(s)r;auto b=s.begin();auto e=s.rbegin();while(e.base()-b>0)r+=s+"\n",*b++=32,*e++=0;return r;}

Assumes input s is a std::string and returns the animated text.

Ungolfed:

auto f(auto s){
  decltype(s)r;
  auto b=s.begin();
  auto e=s.rbegin();
  while(e.base()-b>0){
    r+=s+"\n";
    *b++=32;
    *e++=0;
  }
  return r;
}

Usage:

main(){
  std::string a{"abcdef"};
  std::cout << f(a);
  std::string b{"abcde"};
  std::cout << f(b);
}
\$\endgroup\$
1
\$\begingroup\$

Vim - 14 keystrokes

qqYp^r $x@qq@q


Explanation:

qq  -- record a macro named 'q'
Y   -- Copy current line
p   -- Paste it
^r  -- Replace the first non-space character on the new line with a space
$x  -- Delete the last character on the line
@q  -- Recursively call the 'q' macro
q   -- Stop recording the 'q' macro
@q  -- Run the 'q' macro

Vim automatically kills the macro once we're out of characters

\$\endgroup\$
1
\$\begingroup\$

Snap! - 16 blocks

Snap!

Output is self-centering. The 'wait' is for humans.

\$\endgroup\$
1
\$\begingroup\$

PHP, 91 bytes

<?for(;$i<.5*$l=strlen($s=$_GET[s]);$i++)echo str_pad(substr($s,$i,$l-$i*2),$l," ",2)."\n";

Usage: save in a file and call from the browser:

http://localhost/codegolf/string-middle.php?s=ABCDEFGHIJKLMNOPQRSTUVWXYZ

Raw output:
ABCDEFGHIJKLMNOPQRSTUVWXYZ
 BCDEFGHIJKLMNOPQRSTUVWXY 
  CDEFGHIJKLMNOPQRSTUVWX  
   DEFGHIJKLMNOPQRSTUVW   
    EFGHIJKLMNOPQRSTUV    
     FGHIJKLMNOPQRSTU     
      GHIJKLMNOPQRST      
       HIJKLMNOPQRS       
        IJKLMNOPQR        
         JKLMNOPQ         
          KLMNOP          
           LMNO           
            MN            


http://localhost/codegolf/string-middle.php?s=1ABCDEFGHIJKLMNOPQRSTUVWXYZ

Raw output:
1ABCDEFGHIJKLMNOPQRSTUVWXYZ
 ABCDEFGHIJKLMNOPQRSTUVWXY 
  BCDEFGHIJKLMNOPQRSTUVWX  
   CDEFGHIJKLMNOPQRSTUVW   
    DEFGHIJKLMNOPQRSTUV    
     EFGHIJKLMNOPQRSTU     
      FGHIJKLMNOPQRST      
       GHIJKLMNOPQRS       
        HIJKLMNOPQR        
         IJKLMNOPQ         
          JKLMNOP          
           KLMNO           
            LMN            
             M             
\$\endgroup\$
1
\$\begingroup\$

Mathematica, 71 bytes

Table[#~StringTake~{i,-i},{i,Ceiling[StringLength@#/2]}]~Column~Center&

animate-finding-the-middle

\$\endgroup\$
1
\$\begingroup\$

Stax, 7 bytes

ö÷e╧╤ù◘

Run and debug it

Explanation

|]miTiNt
|]m      map each suffix to:
   iT    remove iteration count elements from right
     iNt pad with iteration count number of spaces on left

Stax, 117 bytes

c%{d
   xitiT|c
   {|,}20*|:xi{xitiTx%|CPFxP
   {|,}20*|:xi{xitiTx%|CPFxitiNtP
   {|,}20*|:xi{xitiTx%|CPFxitiTx%|CP
F

Run and debug it, animated

The more fun version. Since stax supports requestAnimationFrame from js, |, and |: can be used to animate each step.

\$\endgroup\$
1
\$\begingroup\$

Pyth, 11 bytes

.e
:bUkd_._

Test suite

14 bytes to exit without error

\$\endgroup\$
1
\$\begingroup\$

APL (Dyalog Unicode), 25 16 15 bytes

-9 bytes thanks to Jonah's comment!
-1 bytes thanks to Adám!

{⍉↑⍵/¨⍨⌊∘⌽⍨⍳⍴⍵}

Try it online!

This is the dfn taking the string as right input .

⍳⍴⍵ the indices of the input string.
⌊∘⌽⍨ element-wise minimum of the indices with the indices reversed. This is the number of times each character appears.
⍵/¨⍨ repeat each character that many times.
arranges the repeated characters in a 2d matrix, padding shorter strings with spaces.
transposes the matrix.

Try it with step-by-step output!

\$\endgroup\$
4
  • 1
    \$\begingroup\$ After much pondering, I found another approach that might save you bytes too. I'll add explanation later, but basically the idea is to duplicate the letters "vertically" down. Ofc you have to do it horizontally, then transpose. \$\endgroup\$
    – Jonah
    May 11, 2021 at 18:59
  • 1
    \$\begingroup\$ @Jonah thanks a lot, this definitely saved some bytes. I've changed my code according to your comment, but from what I can tell this is now very similar to your J code. \$\endgroup\$
    – ovs
    May 11, 2021 at 21:24
  • \$\begingroup\$ Sixteen each :) \$\endgroup\$
    – Jonah
    May 11, 2021 at 23:57
  • 1
    \$\begingroup\$ (⌽⌊⊢)⌊∘⌽⍨ \$\endgroup\$
    – Adám
    Feb 2, 2022 at 12:54

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.