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

49 Answers 49

1
2
1
\$\begingroup\$

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

\$\endgroup\$
3
  • \$\begingroup\$ Does this work for single-letter words? \$\endgroup\$
    – Neil
    May 17, 2019 at 0:19
  • \$\begingroup\$ @Neil no because I'm bad. I'll fix later. \$\endgroup\$ May 17, 2019 at 0:20
  • \$\begingroup\$ 109 by using newline as delimiter \$\endgroup\$
    – Gymhgy
    May 17, 2019 at 4:55
1
\$\begingroup\$

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!

\$\endgroup\$
2
  • \$\begingroup\$ map g is shorter than (g<$>) \$\endgroup\$
    – Cubic
    May 17, 2019 at 10:17
  • 1
    \$\begingroup\$ Also, if you look at your test case you'll see it doesn't work for one letter words, it turns a into aa \$\endgroup\$
    – Cubic
    May 17, 2019 at 10:20
1
\$\begingroup\$

Scala, 100 bytes

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

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.

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

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
\$\endgroup\$
4
  • \$\begingroup\$ Much shorter than my 12 byter: ¸®Ì+Zs1J +Zg \$\endgroup\$
    – Gymhgy
    May 17, 2019 at 3:07
  • \$\begingroup\$ @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. \$\endgroup\$
    – Shaggy
    May 17, 2019 at 8:01
  • 1
    \$\begingroup\$ @EmbodimentofIgnorance Found a 7 byter \$\endgroup\$
    – Oliver
    May 17, 2019 at 17:21
  • \$\begingroup\$ @Downvoter, why? \$\endgroup\$
    – Shaggy
    Oct 11, 2021 at 9:17
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\$
7
  • \$\begingroup\$ You can remove the whitespace before ">" \$\endgroup\$
    – squid
    May 16, 2019 at 19:40
  • \$\begingroup\$ @squid thanks. I'm on mobile, so whitespace is hard on tio. \$\endgroup\$
    – TFeld
    May 16, 2019 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\$ May 16, 2019 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\$ May 16, 2019 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\$ May 17, 2019 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\$

Brainf**k, 126

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

Try it online!

Could definitely be golfed further.

\$\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\$
1
  • \$\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, 2019 at 17:38
1
\$\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\$
1
\$\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\$
1
\$\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\$
0
\$\begingroup\$

jq, 73 68 bytes

./" "|map((length<2//[./""|.[-1],.[1:-1][],.[0]]|add?)//.)|join(" ")

Try it online!

How?

  . / " "                             # Split on spaces
| map(                                # For each word...
    (
         length<2                     # If it's shorter than 2 letters, emit false
      // [   . / ""                   # Otherwise, emit the word's characters
           | .[-1], .[1:-1][], .[0]]  # ...in the order last, middle, first
      | add?                          # Then re-join the characters into an updated word. If we don't have a list of characters, (if the original was too short), emit nothing
    ) // .                            # If we didn't get a value, emit the word unchanged
  )
| join(" ")
\$\endgroup\$
0
\$\begingroup\$

Factor, 60 bytes

[ " "split [ 1 cut 1 short cut* spin 3append ] map " "join ]

This doesn't run on TIO (Try it Online) because spin postdates build 1525, the one TIO uses. Here's a screenshot of running it in build 1889, the official 0.98 release:

A screenshot of running the above code in the Factor Listener (REPL)

Explanation

It's a quotation (anonymous function) that takes a string from the data stack as input and leaves a string on the data stack as output. Assuming "in a green meadow" is on top of the data stack when this quotation is called...

Snippet Comment Data stack (the bottom is the top)
" "split
Split a string into a sequence of space-delimited strings
{ "in" "a" "green" "meadow" }
[ ... ] map
Apply a quotation to each element of a sequence, collecting the results in a new sequence of the same length
Inside the quotation during the first iteration of map now...
"in"
1 cut
Split a string in two at index 1
"i"
"n"
1 short
The minimum of 1 and the length of the sequence on top of the stack — prevents cut* from trying to cut at an invalid index
"i"
"n"
1
cut*
Like cut, but works from the end of the sequence; not the start
"i"
""
"n"
spin
Swap the object on top of the data stack with the third object from the top of the data stack
"n"
""
"i"
3append
Append three sequences
"ni"
And so forth...
{ "ni" "a" "nreeg" "weadom" }
" "join
Join a sequence of strings into a single string separated by a space
"ni a nreeg weadom"
\$\endgroup\$
0
\$\begingroup\$

Stax, 6 bytes

╡à⌂≤¬)

Run and debug it

Uses newline for the word delimiter

\$\endgroup\$
1
2

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.