# pwaS eht tirsf dna tasl setterl fo hace dorw

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"

• How should punctuation be treated? Hello, world! becomes ,elloH !orldw (swapping punctuation as a letter) or oellH, dorlw! (keeping punctuation in place)? – Phelype Oleinik May 16 at 19:23
• @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. – Comrade SparklePony May 16 at 19:24
• 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? – Adám May 16 at 19:46
• @Adám Any non-alphabetic character. I’ll edit to clarify. – Comrade SparklePony May 16 at 21:36
• @BenjaminUrquhart Yes. You can take input as a function argument if you want as well. – Comrade SparklePony May 16 at 21:44

# TeX, 220 bytes (5 lines, 44 characters each)

Because it's not about the byte count, it's about the quality of the typeset output :-)

{\let~\catcode~A13 \defA#1{~#113\gdef}AGG%
#1{~#113\global\let}GFF\elseGHH\fiAQQ{Q}AI%
1#2#3|{I#2FE{#1}#2#3|H}ACC#1#2|{D{}#2Q|#1 }A
BBH#1 {HI#1FC#1|BH}\gdef\S#1{\iftrueBH#1 Q}}


Try it Online! (Overleaf; not sure how it works)

Full test file:

{\let~\catcode~A13 \defA#1{~#113\gdef}AGG%
#1{~#113\global\let}GFF\elseGHH\fiAQQ{Q}AI%
1#2#3|{I#2FE{#1}#2#3|H}ACC#1#2|{D{}#2Q|#1 }A
BBH#1 {HI#1FC#1|BH}\gdef\S#1{\iftrueBH#1 Q}}

\S{swap the a first and last letters of each word}

pwas eht a tirsf dna tasl setterl fo hace dorw

\S{SWAP THE A FIRST AND LAST LETTERS OF EACH WORD}

\bye


Output:

For LaTeX you just need the boilerplate:

\documentclass{article}
\begin{document}

{\let~\catcode~A13 \defA#1{~#113\gdef}AGG%
#1{~#113\global\let}GFF\elseGHH\fiAQQ{Q}AI%
1#2#3|{I#2FE{#1}#2#3|H}ACC#1#2|{D{}#2Q|#1 }A
BBH#1 {HI#1FC#1|BH}\gdef\S#1{\iftrueBH#1 Q}}

\S{swap the a first and last letters of each word}

pwas eht a tirsf dna tasl setterl fo hace dorw

\S{SWAP THE A FIRST AND LAST LETTERS OF EACH WORD}

\end{document}

• I would love a full explanation of this one. I'm very curious as to how it works! – LambdaBeta yesterday
• @LambdaBeta I can do it, but not right now. Hold on and I'll ping you when I do it :) – Phelype Oleinik yesterday

# JavaScript (ES6),  39  36 bytes

Saved 3 bytes thanks to @FryAmTheEggman

Uses a linefeed as separator.

s=>s.replace(/(.)(.*)(.)/g,'$3$2$1')  Try it online! • (.)(.*)(.) is that the Total Recall emoticon? – MikeTheLiar 2 days ago • @MikeTheLiar Kind of, I guess. :D – Arnauld 2 days ago • The assignment specifies the string contains the separator. – Cees Timmerman yesterday • @CeesTimmerman I'm not sure what you mean. This code expects a linefeed as separator and therefore takes strings with linefeeds as input. (The footer of the TIO link converts spaces to linefeeds and then back to spaces for readability.) – Arnauld yesterday • "given a string of alphabetical ASCII characters as well as one other character to use as a delimiter (to separate each word)" - Nm, i thought it was a separate parameter. – Cees Timmerman yesterday # Retina, 8 5 bytes ,V,,  Try it online! Saved 3 bytes thanks to Kevin Cruijssen! Uses a newline as the separator. We make use of Retina's reverse stage and some limits. The first limit is which matches to apply the reversal to, so we pick all of them with ,. Then we want the first and last letter of each match to be swapped, so we take each letter in the range ,, which translates to a range from the beginning to the end with step size zero. • Dangit, I was just searching through the docs for something like this to update my answer, but you beat me to it. I knew about V, but didn't knew it could be used with the indices 1,-2 like that. Nice one! – Kevin Cruijssen May 16 at 20:23 • @KevinCruijssen I cheated a little and reviewed how limit ranges worked while this was in the sandbox :) I still feel like there should be a better way than inverting a range but I haven't been able to find anything shorter. – FryAmTheEggman May 16 at 20:28 • You're indeed right that it can be shorter without a limit-range, because it seems this 5-byter works (given as example at the bottom of the Step Limits in the docs). – Kevin Cruijssen May 16 at 20:41 • @KevinCruijssen Nice! Can't believe I missed that. – FryAmTheEggman May 16 at 20:51 • So, 5 bytes and only 3 different characters? That's minimalist. – Cœur 2 days ago # Pepe, 107 bytes REEeREeeEeeeeerErEEreREEEeREEEEEEeREEEErEEREEEEEEEreererEEEeererEEEerEEeERrEEEeerEEeerereeerEEEEeEEEReEeree  Try it online! # Python 3, 72 58 bytes print(*[x[-1]+x[1:-1]+x[:x>x[0]]for x in input().split()])  Try it online! • Doesn't work for one letter words (eg a) – TFeld May 16 at 19:37 • @TFeld, fixed.. – alexz02 May 16 at 19:55 # 05AB1E, 10 bytes #vyRćsRćðJ  Try it online! -3 Thanks to @Kevin Cruijssen. # | Split into words. vy | For each word... RćsRć | Reverse, split head, swap, reverse, split tail ðJ | Join by spaces.  • 10 bytes – Kevin Cruijssen May 16 at 19:58 • @KevinCruijssen I honestly want to delete it and give it to you, that was 99% your brainpower on the ordering of the arguments haha. – Magic Octopus Urn May 16 at 20:29 • Found a 9-byter, but it only works in the legacy version: |ʒRćsRćJ, – Kevin Cruijssen May 16 at 21:10 • Too bad we don't have a loop_as_long_as_there_are_inputs, then I would have known an 8-byter: [RćsRćJ, This 8-byter using [ never outputs in theory however, only when you're out of memory or time out like on TIO (and it requires a trailing newline in the input, otherwise it will keep using the last word).. – Kevin Cruijssen May 16 at 21:15 • Unfortunately you need ð¡ as single word input is possible, but ð¡εćsÁì}ðý also works at 10 bytes. – Emigna 2 days ago # laskelH, 71 bytes h=reverse s(x:y:o)=a:h(x:r)where(a:r)=h$y:o
s o=o
f=unwords.map s.words


Try it online!

Example in/output:

Swap the first and last letter in each word
This also works with single letter words like a

It is basically just a straight up implementation in which
I for words consisting of two or more letters cons the head
of the reversed tail on the reverse of the original head consed
on the reversed tail

Note that the rules say that we only have to support one kind
of separator - I am choosing spaces Technically it works with
other whitespace as well, but it will turn everything into spaces
in the end Line endings in this example usage are handled separately
to make the example output look nicer

pwaS eht tirsf dna tasl rettel ni hace dorw
shiT olsa sorkw hitw eingls rettel sordw eikl a

tI si yasicallb tusj a ttraighs pu nmplementatioi ni hhicw
I rof sordw gonsistinc fo owt ro eorm setterl sonc eht deah
fo eht deverser lait no eht eeversr fo eht lriginao deah donsec
no eht deverser lait

eotN that eht suler yas that ew ynlo eavh ot tuppors eno dink
fo reparatos - I ma ghoosinc spaces yechnicallT ti sorkw hitw
rtheo ehitespacw sa ,ellw tub ti lilw nurt gverythine onti spaces
ni eht dne einL sndinge ni shit example esagu era dandleh yeparatels
ot eakm eht example tutpuo kool ricen
$$$$

• The assignment in the where clause can be moved to a binding in guard to save 5 bytes: Try it online! – Laikoni 15 hours ago
• I see what you did there with the name "Haskell" in the title. I did the same thing on my PHP answer. – gwaugh 13 hours ago

# Ruby with -p, 4241 29 bytes

gsub /(\w)(\w*)(\w)/,'\3\2\1'


Try it online!

• We no longer include flags in byte counts – Shaggy May 16 at 21:50
• @Shaggy thanks for the heads up. If you look at my post history it shows I was away for 8 months without any answers, so I've likely missed a few memos during that time, haha – Value Ink May 16 at 21:57
• Pretty sure the consensus was changed more than 8 months ago but just in case you missed it: "non-competing" is also no longer a thing. – Shaggy May 16 at 21:58
• Nicely done. I think under the rules you can use newlines as your delimiter and replace the \ws with .s. – histocrat 2 days ago

## Haskell, 54 bytes

unwords.map f.words
f[a]=[a]
f(a:b)=last b:init b++[a]


Try it online!

# J, 23 17 bytes

({:,1|.}:)&.>&.;:


Try it online!

• Very nice trick to swap the first/last letters by rotating and applying 1 A. ! – Galen Ivanov 2 days ago
• 1&A.&.(1&|.) -> ({:,1|.}:) and then you can remove the ::] – ngn 2 days ago
• Amazing, thank you – FrownyFrog 2 days ago
• Really amazing! Once again I'm amazed how simple and elegant can the solution be, but only after I see it done by someone else. – Galen Ivanov yesterday

# Stax, 8 bytes

Σq╞♪áZN¢


Run and debug it

Uses newlines as word separators.

# Japt-S, 7 bytes

¸®ÎiZÅé


Try it

• Nice! I knew there'd be a shorter way. – Shaggy 2 days ago
• I am impressed. Well done – Embodiment of Ignorance 2 days ago

# Wolfram Language (Mathematica), 58 bytes

StringReplace[#,a:u~~w:u..~~b:u:>b<>w<>a/.{u->Except@#2}]&


Try it online!

-22 bytes from @attinat

-12 bytes from @M.Stern

• 70 bytes using StringReplace with StringExpressions – attinat 2 days ago
• 64 bytes using StringTake instead of StringReplace: StringRiffle[StringSplit@##~StringTake~{{-1},{2,-2},{1}},#2,""]& – Roman yesterday
• Here is a more direct approach: StringReplace[#, a : u ~~ w : u .. ~~ b : u :> b <> w <> a /. {u -> Except@#2}] & – M. Stern 21 hours ago
• { and } are optional :) – M. Stern 20 hours ago
• 55 bytes, also fixes 2-character words – attinat 4 hours ago

# QuadR, 20 bytes

(\w)(\w*)(\w)
\3\2\1


Simply make three capturing groups consisting of 1, 0-or-more, and 1 word-characters, then reverses their order.

Try it online!

# APL+WIN, 50 bytes

(∊¯1↑¨s),¨1↓¨(¯1↓¨s),¨↑¨s←((+\s=' ')⊂s←' ',⎕)~¨' '


Prompts for string and uses space as the delimiter.

Try it online! Courtesy of Dyalog Classic

# Whitespace, 179 bytes

[N
S S S N
_Create_Label_OUTER_LOOP][S S S N
_Push_n=0][N
S S T   N
_Create_Label_INNER_LOOP][S N
S _Duplicate_n][S N
S _Duplicate_n][S N
S _Duplicate_n][T   N
T   S _Read_STDIN_as_character][T   T   T   _Retrieve_input][S S S T    S T T   N
_Push_11][T S S T   _Subtract_t=input-11][N
T   T   S S N
_If_t<0_jump_to_Label_PRINT][S S S T    N
_Push_1][T  S S S _Add_n=n+1][N
S N
T   N
_Jump_to_Label_INNER_LOOP][N
S S S S N
_Create_Label_PRINT][S S S T    N
_Push_1][T  S S T   _Subtract_n=n-1][S N
S _Duplicate_n][S N
S _Duplicate_n][N
T   S N
_If_n==0_jump_to_Label_PRINT_TRAILING][T    T   T   _Retrieve][T    N
S S _Print_as_character][S S S N
_Push_s=0][N
S S S T N
_Create_Label_PRINT_LOOP][S S S T   N
_Push_1][T  S S S _Add_s=s+1][S N
S _Duplicate_s][S T S S T   S N
_Copy_0-based_2nd_n][T  S S T   _Subtract_i=s-n][N
T   S N
_If_0_Jump_to_Label_PRINT_TRAILING][S N
S _Duplicate_s][T   T   T   _Retrieve][T    N
S S _Print_as_character][N
S T S T N
_Jump_to_Label_PRINT_LOOP][N
S S N
_Create_Label_PRINT_TRAILING][S S S N
_Push_0][T  T   T   _Retrieve][T    N
S S _Print_as_character][S S S T    S S T   N
_Push_9_tab][T  N
S S _Print_as_character][N
S N
S N
_Jump_to_Label_OUTER_LOOP]


Letters S (space), T (tab), and N (new-line) added as highlighting only.
[..._some_action] added as explanation only.

Tab as delimiter. Input should contain a trailing newline (or tab), otherwise the program doesn't know when to stop, since taking input in Whitespace can only be done one character at a time.

Try it online (with raw spaces, tabs, and new-lines only).

Explanation in pseudo-code:

Whitespace only has a stack and a heap, where the heap is a map with a key and value (both integers). Inputs can only be read one integer or character at a time, which are always placed in the heap as integers, and can then be received and pushed to the stack with their defined heap-addresses (map-keys). In my approach I store the entire word at the heap-addresses (map-keys) $$\[0, ..., \text{word_length}]\$$, and then retrieve the characters to print one by one in the order we'd want after a tab (or newline) is encountered as delimiter.

Start OUTER_LOOP:
Integer n = 0
Start INNER_LOOP:
Character c = STDIN as character, saved at heap-address n
If(c == '\t' OR c == '\n'):
n = n + 1
Go to next iteration of INNER_LOOP

PRINT:
n = n - 1
If(n == 0): (this means it was a single-letter word)
Character c = get character from heap-address n
Print c as character
Integer s = 0

Start PRINT_LOOP:
s = s + 1
If(s - n == 0):
Character c = get character from heap-address s
Print c as character
Go to next iteration of PRINT_LOOP

PRINT_TRAILING:
Character c = get character from heap-address 0
Print c as character
Print '\t'
Go to next iteration of OUTER_LOOP


The program terminates with an error when it tries to read a character when none is given in TIO (or it hangs waiting for an input in some Whitespace compilers like vii5ard).

# Japt-S, 10 bytes

Convinced there has to be a shorter approach (and I was right) but this'll do for now.

¸ËhJDg)hDÌ


Try it

¸ËhJDg)hDÌ     :Implicit input of string
¸              :Split on spaces
Ë             :Map each D
h            :  Set the character at
J           :    Index -1 to
Dg         :    The first character in D
)        :  End set
h       :  Set the first character to
DÌ     :    The last character in D
:Implicit output, joined by spaces

• Much shorter than my 12 byter: ¸®Ì+Zs1J +Zg – Embodiment of Ignorance May 17 at 3:07
• @EmbodimentofIgnorance, that's where I started, too, but it would have failed on single character words. You could save a byte on that, though, with ¸®ÎiZÌ+Zs1J. – Shaggy 2 days ago
• @EmbodimentofIgnorance Found a 7 byter – Oliver 2 days ago

# PowerShell, 37 bytes

$args-replace'(\w)(\w*)(\w)','$3$2$1'


Try it online!

# Perl 5-p, 24 bytes

s/(\w)(\w*)(\w)/$3$2$1/g  Try it online! • You can get it to 21 by using the newline as separator: Try it online! – wastl 2 days ago ## Batch, 141 bytes @set t= @for %%w in (%*)do @call:c %%w @echo%t% @exit/b :c @set s=%1 @if not %s%==%s:~,1% set s=%s:~-1%%s:~1,-1%%s:~,1% @set t=%t% %s%  Takes input as command-line parameters. String manipulation is dire in Batch at best, and having to special-case single-letter words doesn't help. # C# (Visual C# Interactive Compiler), 90 bytes n=>n.Split().Any(x=>WriteLine(x.Length<2?x:x.Last()+x.Substring(1,x.Length-2)+x[0])is int)  Uses newline as delimiter, though really any whitespace can be used. Try it online! • SelectMany (that is, map and flatten) for 84 bytes, but outputs a single trailing space. Try it online! – someone 2 days ago # Icon, 76 bytes link segment procedure f(s) w:=!seglist(s,' ')&w[1]:=:w[-1]&writes(w)&\x end  Try it online! # Java, 110 109 bytes -1 bytes by using a newline for a delimeter s->{int l;for(var i:s.split("\n"))System.out.println(i.charAt(l=i.length()-1)+i.substring(1,l)+i.charAt(0));}  TIO • Does this work for single-letter words? – Neil May 17 at 0:19 • @Neil no because I'm bad. I'll fix later. – Benjamin Urquhart May 17 at 0:20 • 109 by using newline as delimiter – Embodiment of Ignorance 2 days ago # Haskell, 75 74 bytes Fixed a bug pointed at by Cubic and also golfed down 1 byte. f=unwords.map(#v).words x#g=g(r$tail x)++[x!!0]
r=reverse
v[]=[]
v x=r$x#r  Try it online! • map g is shorter than (g<$>) – Cubic 2 days ago
• Also, if you look at your test case you'll see it doesn't work for one letter words, it turns a into aa – Cubic 2 days ago

# Scala, 100 bytes

(b:String,c:String)=>b.split(c)map(f=>f.tail.lastOption++:(f.drop(1).dropRight(1)+f.head))mkString c


# T-SQL, 126 bytes

SELECT STRING_AGG(STUFF(STUFF(value,1,1,RIGHT(value,1)),LEN(value),1,LEFT(value,1)),' ')
FROM STRING_SPLIT((SELECT*FROM t),' ')


Input is via a pre-existing table t with varchar field v, per our IO standards.

Reading from back to front, STRING_SPLIT breaks a string into individual rows via a delimiter, STUFF modifies the characters at the specified positions, then STRING_AGG mashes them back together again.

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

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

# Python 2, 67666461 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, 636158 57 bytes

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


Try it online!

• You can remove the whitespace before ">" – squid May 16 at 19:40
• @squid thanks. I'm on mobile, so whitespace is hard on tio. – TFeld May 16 at 19:43
• Your 58-byte version is now an exact (except for the variable name) copy of alexz02's latest edit from 20 minutes ago – Kevin Cruijssen May 16 at 20:15
• 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. – Kevin Cruijssen May 16 at 20:32
• 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]. – Erik the Outgolfer 2 days ago

# 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, ' ';
}
`