30
\$\begingroup\$

Or, "Swap the first and last letters of each word"

Your challenge is to, given a string of alphabetical ASCII characters as well as one other character to use as a delimiter (to separate each word), swap the first and last letters of each word. If there is a one-character word, leave it alone.

The examples/testcases use the lowercase letters and the space as the delimiter.

You do not need to handle punctuation; all of the inputs will only consist of the letters a through z, separated by a delimiter, all of a uniform case.

For example, with the string "hello world":

Input string: "hello world"
Identify each word: "[hello] [world]"
Identify the first and last letters of each word: "[[h]ell[o]] [[w]orl[d]]"
Swap the first letters of each word: "[[o]ell[h]] [[d]orl[w]]"
Final string: "oellh dorlw"

NOTE: the delimiter does not need to be inputted separately. The delimiter is just the character used to separate words. It can be anything. I wanted to leave options open for creative golfers, so I did not want to limit it to just spaces or new lines. The delimiter is just a character that separates words in the input string.

Test cases:

"swap the first and last letters of each word" -> "pwas eht tirsf dna tasl setterl fo hace dorw"
"hello world" -> "oellh dorlw"
"test cases" -> "test sasec"
"programming puzzles and code golf" -> "grogramminp suzzlep dna eodc folg"
"in a green meadow" -> "ni a nreeg weadom"
"yay racecar" -> "yay racecar"
\$\endgroup\$
  • 3
    \$\begingroup\$ How should punctuation be treated? Hello, world! becomes ,elloH !orldw (swapping punctuation as a letter) or oellH, dorlw! (keeping punctuation in place)? \$\endgroup\$ – Phelype Oleinik May 16 at 19:23
  • 3
    \$\begingroup\$ @PhelypeOleinik You do not need to handle punctuation; all of the inputs will only consist of the letters a through z, and all a uniform case. \$\endgroup\$ – Comrade SparklePony May 16 at 19:24
  • 4
    \$\begingroup\$ Second paragraph reads as well as one other character to use as a delimiter while the fourth reads separated by spaces. Which one is it? \$\endgroup\$ – Adám May 16 at 19:46
  • \$\begingroup\$ @Adám Any non-alphabetic character. I’ll edit to clarify. \$\endgroup\$ – Comrade SparklePony May 16 at 21:36
  • 1
    \$\begingroup\$ @BenjaminUrquhart Yes. You can take input as a function argument if you want as well. \$\endgroup\$ – Comrade SparklePony May 16 at 21:44

43 Answers 43

1
\$\begingroup\$

SNOBOL4 (CSNOBOL4), 90 bytes

I	R =
	INPUT LEN(1) . L REM . M	:F(END)
	M ARB . M RPOS(1) REM . R
	OUTPUT =R M L	:(I)
END

Try it online!

Takes input separated by newlines; can be either uppercase or lowercase.

I R =					;* set R to empty string
  INPUT LEN(1) . L REM . M	:F(END)	;* take first character and set to L, and set the
					;* REMainder to M
  M ARB . M RPOS(1) REM . R		;* match an ARBitrary (possibly empty) run
					;* of characters to M up to but excluding the last character
					;* and save the last character to R
					;* if M is empty, (i.e., a one-letter word), then this fails 
					;* and nothing happens, so M remains empty and R remains empty
  OUTPUT =R M L	:(I)			;* output Right, Middle, Left, then goto I.
END

(previous version)

SNOBOL4 (CSNOBOL4), 92 bytes

I	R =M =
	INPUT LEN(1) . L ('' | ARB . M LEN(1) . R) RPOS(0)	:F(END)
	OUTPUT =R M L	:(I)
END

Try it online!

This is thematically the same, clearly, but suffers from using FAILURE as the termination status, preventing us from using FAILURE as a no-op as we do in the above. This then forces us to set M = as well as R =, which is 3 bytes.

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

PowerShell, 50 bytes

-split"$args"|%{$_-replace'^(.)(.*)(.)$','$3$2$1'}

Try it online!

Uses regex to replace each word with a captured first and last letter surrounding the original core. If it's a single character, replace will find nothing and leave it alone.

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

Python 2, 67 66 64 61 60 bytes

lambda s:' '.join(w[1:][-1:]+w[1:-1]+w[0]for w in s.split())

Try it online!

-1 byte, thanks to squid

-1 byte, thanks to Erik the Outgolfer


Python 3, 63 61 58 57 bytes

print(*[w[1:][-1:]+w[1:-1]+w[0]for w in input().split()])

Try it online!

\$\endgroup\$
  • \$\begingroup\$ You can remove the whitespace before ">" \$\endgroup\$ – squid May 16 at 19:40
  • \$\begingroup\$ @squid thanks. I'm on mobile, so whitespace is hard on tio. \$\endgroup\$ – TFeld May 16 at 19:43
  • \$\begingroup\$ Your 58-byte version is now an exact (except for the variable name) copy of alexz02's latest edit from 20 minutes ago \$\endgroup\$ – Kevin Cruijssen May 16 at 20:15
  • 5
    \$\begingroup\$ True. I was mentioning it merely as a FYI. :) There isn't any rule disqualifying duplicated answers when both users independently came to the same solutions. \$\endgroup\$ – Kevin Cruijssen May 16 at 20:32
  • 1
    \$\begingroup\$ The way you've chosen to account for 1-letter words might prevent you from seeing that this also works, since getting there involves two steps: 1) replace w[:w>w[0]] with w[:-1][:1]; this works because it firstly removes the last character, and, if the word only has one letter, the last character is also the first 2) you then move the mechanism to the other side, so that you have a [0] instead of a [-1]. \$\endgroup\$ – Erik the Outgolfer May 17 at 21:29
1
\$\begingroup\$

PHP, 73 bytes

foreach(explode(' ',$argn)as$w){[$w[0],$w[-1]]=[$w[-1],$w[0]];echo"$w ";}

Try it online!

Using PHP 7.1's Square bracket syntax for array destructuring to swap values.

Ungolfed:

foreach( explode( ' ', $argn ) as $w ) {
  [ $w[0], $w[-1] ] = [ $w[-1], $w[0] ];
  echo $w, ' ';
}
\$\endgroup\$
1
\$\begingroup\$

Jelly, 9 bytes

ḲṪ;ṙ1$Ɗ€K

Try it online!

Explanation

ḲṪ;ṙ1$Ɗ€K | monadic link taking the string as input

Ḳ         | split at spaces
      Ɗ€  | for each word, do the following:
 Ṫ        | - pop the last letter
  ;ṙ1$    | - concatenate to the remaining letters rotated left once
        K | finally, join with spaces
\$\endgroup\$
1
\$\begingroup\$

Z80Golf, 43 bytes

00000000: 2100 c0cd 0380 3822 5745 cd03 8038 09fe  !.....8"WE...8..
00000010: 2028 0570 4723 18f2 736b 707e 23a7 2803   (.pG#..skp~#.(.
00000020: ff18 f87a ff3e 20ff 18d6 76              ...z.> ...v

Try it online!

Corresponding assembly:

mainloop:
    ld hl, $c000
    call $8003
    jr c, hlt
    ld d, a
    ld b, l ; handle 1-character words
inputloop:
    call $8003
    jr c, endinput
    cp $20
    jr z, endinput
    ld (hl), b ; don't store the last character
    ld b, a
    inc hl
    jr inputloop
endinput:
    ld (hl), e ; always 0
    ld l, e
    ld (hl), b
outputloop:
    ld a, (hl)
    inc hl
    and a
    jr z, endoutput
    rst $38
    jr outputloop
endoutput:
    ld a, d
    rst $38
    ld a, $20
    rst $38
    jr mainloop
hlt:
    halt
\$\endgroup\$
1
\$\begingroup\$

Rust, 110 bytes

|a:&str|{for b in a.split(' '){let l=b.len()-1;if l>0{print!("{}{}",&b[l..],&b[1..l])}print!("{} ",&b[0..1])}}

Try it online!

A surprisingly long, but nicer solution that returns instead of printing (126 bytes):

|a:&str|->String{a.split(' ').flat_map(|b|{let mut q:Vec<_>=b.chars().collect();q.swap(0,b.len()-1);q.push(' ');q}).collect()}

Try it online!

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

C (gcc), 62 bytes

t;*s;f(int*i){for(s=i;*++i;i[1]>64||(t=*i,*i=*s,*s=t,s=i+2));}

I wanted to use a xor swap but that fails if a word is only one character long.

Try it online

\$\endgroup\$
  • \$\begingroup\$ Suggest i[1]<65?t=*i,*i=*s,*s=t,s=i+2:0 instead of i[1]>64||(t=*i,*i=*s,*s=t,s=i+2) \$\endgroup\$ – ceilingcat Sep 13 at 17:38
0
\$\begingroup\$

Brainf**k, 126

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

Try it online!

Could definitely be golfed further.

\$\endgroup\$
0
\$\begingroup\$

Julia 1.0, 75 bytes

x->join([(n=length(s);n<2 ? s : s[n]*s[2:n-1]*s[1]) for s in split(x)]," ")

Try it online!

\$\endgroup\$
0
\$\begingroup\$

brainfuck, 71 67 49 47 bytes

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

Try it online!

This code uses a few cheats, so i don't know if it is competing. The separator in the input is a 0x01. The input needs an extra trailing separator, otherwise the last word won't be printed.

code:

+[                  enter the loop / the first round only the last three commands of the main loop are interesting
  -[                if input is not 0x01
    +               restore character
    >>              go to exit if
  ]
  >[                else
    <<.[-]          print and delete last character
    <[<]>>[.>]      print all characters starting at the second
    <[<]>[.[>]]     print first character and go to end if word is longer than one character
    .               print null (space)
    >>>             leave a zero cell and go to exit else
  ]
  <+                set new else marker
  <                 go to new input location
  ,                 input next character
]
\$\endgroup\$
0
\$\begingroup\$

If halting is not necessary:

Aheui (esotope), 174 bytes

삭붵뱷뛰빠쇡붷뼤쎄투@싼사쑫
ByLe쪼gen@처쇠모코커
DUST오멓@@@@푸셴쒼섣
@@@@쇡뽀@@@삳멓@샨@맣

Try it online! press 'start' butten in TIO again to halt manually.

If halting is necessary:

Aheui (esotope), 225 bytes

살뷕볙눠쀄삭붵뱷뛰빠쇡붷빠쎄투@싼사쑫
By@@@@@야빠속@@@수처쇠모오어
Legen@@먷초더헤셜썰뻐푸쉰썬@셛
DUST@@솩뽀사뫼섁쀠우삳멓산멓

Try it online!

In this version, following space after input is necessary. fixed. Now it is OK to not finish with space.

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

JavaScript (ES6), 68 bytes

s=>s.split(" ").map(e=>e[a=e.length-1]+e.substr(1,a)+e[0]).join(" ")

Ungolfed:

s=>                                                  //function declaration
  s                                                  //input
   .split(" ")                                       //array of words
              .map(                                  //for each word
                   e=>                               //function declaration
                      e[a=e.length-1]+               //connect the last character,
                                      e.substr(1,a)+ //middle substring,
e[0]                                                 //and the first character.
    )                                                //then,
     .join(" ")                                      //connect modified words back
\$\endgroup\$
  • \$\begingroup\$ This does not work: TIO. The middle substr should have one less character: s=>s.split(' ').map(e=>e[a=e.length-1]+e.substr(1,a-1)+e[0]).join(' '). This still does not deal with single letter words. \$\endgroup\$ – Johan du Toit May 20 at 9:57
  • \$\begingroup\$ fixed: s=>s.split(' ').map(e=>e[a=e.length-1]+e.substr(1,a-1)+(a?e[0]:"")).join(' ') \$\endgroup\$ – Johan du Toit May 20 at 11:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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