43
\$\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\$
    – sporkl
    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\$
    – sporkl
    May 16, 2019 at 21:36
  • 1
    \$\begingroup\$ @BenjaminUrquhart Yes. You can take input as a function argument if you want as well. \$\endgroup\$
    – sporkl
    May 16, 2019 at 21:44

57 Answers 57

1
2
2
\$\begingroup\$

><> (Fish), 80 78 bytes

3:i&1+:i:'!'(?v$4p30.
$&p4{g4:-1v?(0/p4
. 1ap31'v'/
|.!00+1p4$' ':/
"/"
o>:?!;

Saved 2 bytes trying to fix handling 1-letter words

Try it

enter image description here

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

Thunno 2 , 6 bytes

OıḢsṾƤ

Attempt This Online!

Explanation

OıḢsṾƤ  # Implicit input
O       # Split on spaces
 ı      # Map over the list:
  Ḣ     #  Extract the first character
   s    #  Swap so the rest is on top
    Ṿ   #  Rotate it right once
     Ƥ  #  Append the first character
        # Join the list by spaces
        # Implicit output
\$\endgroup\$
2
\$\begingroup\$

Arturo, 37 bytes

$=>[replace&{/(\w)(\w*)(\w)}"$3$2$1"]

Try it!

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

JavaScript (Node.js), 72 bytes

Solution without regex = two times longer!

s=>s.split` `.map(w=>w[w.length-1]+w.slice(1,-1)+(w[1]?w[0]:"")).join` `

Try it online!


More functional programming approach (81 bytes) :

s=>s.split` `.map(w=>[...w].map((c,i)=>i%(l=w.length-1)?c:w[l-i]).join``).join` `
\$\endgroup\$
2
  • 1
    \$\begingroup\$ s.split` `.map(...).join` ` can be s.replace(/\S+/g,...) (technically using RegEx but not for the hard part of the challenge), w[w.length-1] can be w.at(-1) (though .at() is not available on TIO since the site hasn't been updated in years and still uses Node.js 11; I usually use Attempt This Online! but it is currently offline) \$\endgroup\$
    – noodle man
    Jun 26 at 13:26
  • \$\begingroup\$ @noodleman Oh! Thank you for the tips! I'll see if i can find a reliable and convenient way for me to use newer versions of JS :) Regarding replace, i'm not very fond because it uses regex which i try to not use in this solution. Without this self-imposed-constraint i would be expected to do way much shorter (regarding others' solutions) and this would be less fun for me because i prefer functional algorithms :/ \$\endgroup\$
    – Fhuvi
    Jun 26 at 13:48
2
\$\begingroup\$

Vyxal S, 31 bitsv2, 3.875 bytes

⌈ƛḣǔp

Try it Online!

Ports Thunno 2.

Explained

⌈ƛḣǔp
⌈ƛ     # To each word after splitting on spaces
  ḣ    #   Push the first character, then the rest
   ǔ   #   Rotate right once 
    p  #   Prepend to the first character
# The S flag joins on spaces.
\$\endgroup\$
1
\$\begingroup\$

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!

\$\endgroup\$
1
  • \$\begingroup\$ SelectMany (that is, map and flatten) for 84 bytes, but outputs a single trailing space. Try it online! \$\endgroup\$ May 17, 2019 at 8:17
1
\$\begingroup\$

Icon, 76 bytes

link segment
procedure f(s)
w:=!seglist(s,' ')&w[1]:=:w[-1]&writes(w)&\x
end

Try it online!

\$\endgroup\$
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\$

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\$
1
\$\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\$
2
  • \$\begingroup\$ [ " "split [ 1 cut -1 rotate prepend ] map " "join ] for 52 bytes with sequences.extras seems to work. I've never used Factor before but I've been meaning to try it out, code-golf seems like a good place to start \$\endgroup\$
    – noodle man
    Jun 26 at 14:22
  • 1
    \$\begingroup\$ @noodleman Unfortunately this crashes on inputs that have a single-letter word, since rotating an empty sequence causes an error. Glad to hear you're interested! It would be fantastic to have some competition in Factor. :) Feel free to join the Factor Discord -- I am happy to answer questions. \$\endgroup\$
    – chunes
    Jun 27 at 1:25
1
\$\begingroup\$

Stax, 6 bytes

╡à⌂≤¬)

Run and debug it

Uses newline for the word delimiter

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

Lexurgy, 30 bytes

s:
[]$1 ([]*)$2 []$3=>$3 $2 $1
\$\endgroup\$
1
\$\begingroup\$

GolfScript, 19 15 bytes

-4 bytes by splitting on newlines

Input is taken seperated by newlines.

n/{[)\(]''+}%n*

Try it online!

Explanation

n/{[)\(]''+}%n* # whole program
n/              # split the <implicit> input by newlines
    {        }% # for each value in the split input
     [)  ]      # take the last item of the string
       \        # swap stack ; stack: <last letter> <word without last letter>
        (       # take the first item out of the string ; stack: <last letter> <word> <first letter>
          ''+    # concatenate into charcodes
              n* # join by newlines
\$\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\$
1
2

Your Answer

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

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