# Simple String Reflection

Let's start by defining a reflection of a character in a string:

Given a string with distinct lowercase alphabetical letters with no spaces such as abcdefg, define a reflection of a letter in the string c as moving it (without changing the order of any other letter) to a new place in the string such that the number of letters originally to the right of it is now the number of letters to the left of it.

Thus, a reflection of the letter c in abcdefg would be abdecfg. Explanation: there were 4 letters to the right of c and now, there are 4 letters to the left of c.

Some more examples:

Reflecting the character e in myfriend would form the string myefrind

Reflecting the character a in axyz would form the string xyza.

Reflecting the character b in abc would form the string abc.

Reflecting the character d in d would form the string d.

Reflecting the character e in ef would form the string fe.

For more information or to try out some test cases, here is a (somewhat long) program I wrote in C++.

## The Challenge

Given a string with distinct lowercase letters, go through each character alphabetically and "reflect" it in the string.

Clarifications: The letters in the string are from a-z, there are no spaces, the letters are unique, and the string is at least 1 letter long and at most 26 letters long.

## Examples

Input: dcba. Output: dcba.

Reason: First, reflect the a as it is the character in the string that comes earliest in the alphabet. You will get adcb. Then, reflect the b as it comes next in the alphabet, to get badc. Then, reflect the c to get cbad, and then the d to get dcba.

Input: myface. Output: fyecma.

Hint: Go through the letters in the order a, c, e, f, m, y.

Input: a. Output: a.

Input: acb. Output: bac.

Input: cwmfjordbankglyphsvextquiz. Output: ieabhqzugdltkfnvpjxsormycw.

## Scoring

• The input and output can be given by any convenient method.
• Either a full program or a function are acceptable. If a function, you can return the output rather than printing it.
• Standard loopholes are forbidden.
• This is so all usual golfing rules apply, and the shortest code (in bytes) wins.
• Accepting ~100 hours after posting.

## Current Winner

<style>body { text-align: left !important} #answer-list { padding: 10px; width: 290px; float: left; } #language-list { padding: 10px; width: 290px; float: left; } table thead { font-weight: bold; } table td { padding: 5px; }</style><script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="language-list"> <h2>Shortest Solution by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr> </thead> <tbody id="languages"> </tbody> </table> </div> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr> </thead> <tbody id="answers"> </tbody> </table> </div> <table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr> </tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr> </tbody> </table><script>var QUESTION_ID = 162891; var ANSWER_FILTER = "!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe"; var COMMENT_FILTER = "!)Q2B_A2kjfAiU78X(md6BoYk"; var OVERRIDE_USER = 12012; var answers = [], answers_hash, answer_ids, answer_page = 1, more_answers = true, comment_page; function answersUrl(index) { return "https://api.stackexchange.com/2.2/questions/" + QUESTION_ID + "/answers?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + ANSWER_FILTER; } function commentUrl(index, answers) { return "https://api.stackexchange.com/2.2/answers/" + answers.join(';') + "/comments?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + COMMENT_FILTER; } function getAnswers() { jQuery.ajax({ url: answersUrl(answer_page++), method: "get", dataType: "jsonp", crossDomain: true, success: function (data) { answers.push.apply(answers, data.items); answers_hash = []; answer_ids = []; data.items.forEach(function(a) { a.comments = []; var id = +a.share_link.match(/\d+/); answer_ids.push(id); answers_hash[id] = a; }); if (!data.has_more) more_answers = false; comment_page = 1; getComments(); } }); } function getComments() { jQuery.ajax({ url: commentUrl(comment_page++, answer_ids), method: "get", dataType: "jsonp", crossDomain: true, success: function (data) { data.items.forEach(function(c) { if (c.owner.user_id === OVERRIDE_USER) answers_hash[c.post_id].comments.push(c); }); if (data.has_more) getComments(); else if (more_answers) getAnswers(); else process(); } }); } getAnswers(); var SCORE_REG = /<h\d>\s*([^\n,<]*(?:<(?:[^\n>]*>[^\n<]*<\/[^\n>]*>)[^\n,<]*)*),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/; var OVERRIDE_REG = /^Override\s*header:\s*/i; function getAuthorName(a) { return a.owner.display_name; } function process() { var valid = []; answers.forEach(function(a) { var body = a.body; a.comments.forEach(function(c) { if(OVERRIDE_REG.test(c.body)) body = '<h1>' + c.body.replace(OVERRIDE_REG, '') + '</h1>'; }); var match = body.match(SCORE_REG); if (match) valid.push({ user: getAuthorName(a), size: +match[2], language: match[1], link: a.share_link, }); else console.log(body); }); valid.sort(function (a, b) { var aB = a.size, bB = b.size; return aB - bB }); var languages = {}; var place = 1; var lastSize = null; var lastPlace = 1; valid.forEach(function (a) { if (a.size != lastSize) lastPlace = place; lastSize = a.size; ++place; var answer = jQuery("#answer-template").html(); answer = answer.replace("{{PLACE}}", lastPlace + ".") .replace("{{NAME}}", a.user) .replace("{{LANGUAGE}}", a.language) .replace("{{SIZE}}", a.size) .replace("{{LINK}}", a.link); answer = jQuery(answer); jQuery("#answers").append(answer); var lang = a.language; lang = jQuery('<a>'+lang+'</a>').text(); languages[lang] = languages[lang] || {lang: a.language, lang_raw: lang.toLowerCase(), user: a.user, size: a.size, link: a.link}; }); var langs = []; for (var lang in languages) if (languages.hasOwnProperty(lang)) langs.push(languages[lang]); langs.sort(function (a, b) { if (a.lang_raw > b.lang_raw) return 1; if (a.lang_raw < b.lang_raw) return -1; return 0; }); for (var i = 0; i < langs.length; ++i) { var language = jQuery("#language-template").html(); var lang = langs[i]; language = language.replace("{{LANGUAGE}}", lang.lang) .replace("{{NAME}}", lang.user) .replace("{{SIZE}}", lang.size) .replace("{{LINK}}", lang.link); language = jQuery(language); jQuery("#languages").append(language); } }</script>

• Could anyone give me insight as to whether this puzzle is okay? It's my second one here (my first was closed as off-topic...whoops). I tried to make it really complete, but I'm not sure if I'm missing anything. I'd really like to improve and have fun on this SE! Thanks guys :D Apr 20, 2018 at 2:57
• This looks good. I might give a few longer examples (in particular, it might be good for the first examples section to present more than what are seemingly edge cases). Apr 20, 2018 at 3:36
• Clarification request: "the letters are unique" means each letter occurs only once in input, is that correct?
– GPS
Apr 20, 2018 at 5:06
• Can we take the input and output in uppercase instead of lowercase? Apr 20, 2018 at 7:05
• @NL628 By the way, if you want to get insight on a challenge before posting it here, then post it in the Sandbox. Apr 20, 2018 at 12:01

# Brain-Flak, 188 bytes

<>((((()()()){}){}()){}){(({}[()])<({}[(((((()()()()()){}){}){})()){}{}])<>{<>(({})<({}<>({}<>))((){[()](<{}>)}{}){{}(<({}<([]<<>{({}<>)<>}<>>){({}[()]<({}<>)<>>)}{}>)>)}{}>)<>}<>{}<>>)}<>


Try it online!

In addition to the reflections described in the challenge specification, this code also reverses the string exactly 26 times. This has no effect on the final output.

# Push 26
<>((((()()()){}){}()){})

# Do 26 times:
{(({}[()])<

# Subtract 122 from counter to get negative lowercase letter
({}[(((((()()()()()){}){}){})()){}{}])

# For each character in string:
<>{

# Keep a copy of pivot letter on the third stack
<>(({})<

# Move next letter to other stack and compare to pivot
({}<>({}<>))

# If letters are equal:
((){[()](<{}>)}{}){

# Keep current letter separate from this transformation
{}(<({}<

# While keeping a copy of current stack height:
([]<

# Move all letters to one stack
<>{({}<>)<>}<>

>)

# Move a number of letters equal to old stack height back
{({}[()]<({}<>)<>>)}{}

>)>)

}{}>)<>

}

# Destroy pivot letter
<>{}<>

>)}

# Switch stack for output
<>

• Wow that's pretty amazing. I can't even understand it :O +1 Apr 20, 2018 at 3:51

# 05AB1E, 20 17 bytes

{vð.øy¡€áÂ€gsJ£yý


Try it online!

Explanation

With example for the first iteration of myface

{v                  # for each char y in sorted input
ð.ø               # surround current string with spaces
# STACK: ' myface '
y¡             # split at current letter
# STACK: [' myf', 'ce ']
€á           # remove non-letters
# STACK: ['myf','ce']
Â€g        # get the length of each string in the pair, reversed
# STACK: ['myf','ce'], [2,3]
sJ      # join the pair back to a string
£     # split into 2 pieces of the calculated sizes
# STACK: ['my','fce']
yý   # join on the current char y
# STACK: 'myafce'


The string is surrounded with spaces each iteration as splitting on the first or last letter of the string would result in a length-1 list otherwise and the merge wouldn't include that letter.

• 17 bytes?!??!! AMAZING..yet mnemonic is beating you by just one byte :P Apr 20, 2018 at 17:44
• Mmmm... Wow, only thing I could see is removing the surround with spaces. Seems odd we can't find another alternative to that. Apr 23, 2018 at 0:11
• @MagicOctopusUrn: It's the shortest way I've found of handling a split of the first or last character. It does feel like a lot of bytes just for that though Apr 23, 2018 at 6:29

# Pyth, 181619 16 bytes

VSQ=QXx_QN-QNN)Q


Try it here

### Explanation

VSQ=QXx_QN-QNN)Q
VSQ           )       For each character (N) in the sorted input (Q)...
-QN         ... remove the character from Q...
x_QN            ... get the reflected position...
X       N        ... insert N...
=Q                 ... and save the result into Q.
Q      Output the final result.

• Wow 16 bytes? I would upvote, but sadly I've reached my daily voting limit. Will do in 6 hours :P Apr 20, 2018 at 17:44

# Python 3, 80 73 bytes

Thanks to Esolanging Fruit for reminding me that functions can return by modifying their argument.

lambda x:[x.insert(len(x)+~x.index(i),x.remove(i)or i)for i in sorted(x)]


Try it online!

Takes input as a list of characters.

• Wow I wrote an answer in C++ and Python 3 also. My Python 3 answer was exactly twice as long as yours... +1 Apr 20, 2018 at 3:52

# Python 2, 70 bytes

def f(t):
for c in sorted(t):i=t.index(c);l=len(t)+~i;t[l:l]=t.pop(i)


Try it online!

Modifies the input list

# Retina 0.8.2, 61 bytes

$a {(.)(.*)\1$
$2$.$*_$1$1 +(.)_(_*.)$2$1 }T_ll!.$
!



Try it online! Link includes test cases. Explanation:

$a  Start the loop at a. {(.)(.*)\1$
$2$.$*_$1$1  If the input contains the current letter, move it to the end, with a string of _s representing its original position. +(.)_(_*.)$2$1  For each _ move the letter back one character. }T_ll!.$


Increment the letter. After z change it to a ! so it doesn't match anything and the loop ends.

!



Delete the !.

# Java 8, 14096928887 85 bytes

s->{for(char c=9;++c>0;){int i=s.indexOf(c);if(i>=0)s.add(s.size()+~i,s.remove(i));}}


-44 bytes creating a port of @TFeld's Python 2 answer.
-6 bytes thanks to @OlivierGrégoire.

Modifies the input List instead of creating a new one.

Explanation:

Try it online.

s->{                     // Method with ArrayList<Character> parameter and no return-type
for(char c=9;++c>0;){  //  Loop over all characters known
//  (except for the first 9 unprintables)
int i=s.indexOf(c);  //   Index of the character, or -1 of it isn't present
if(i>=0)             //   If the current character is present in the List
//    Change the position of this character to index l-i-1,
//    (where l is the size of the input-List)

• @OlivierGrégoire Thanks. And 1 more looping over more than just the alphabet characters. :) Apr 20, 2018 at 8:55
• Well, if you go that road, for(char c=9;++c>1;) is better ;-) Apr 20, 2018 at 8:57
• @OlivierGrégoire Ah of course, char also wraps around like Integer.MAX_VALUE + 1 == Integer.MIN_VALUE.. Smart! Apr 20, 2018 at 8:58
• @OlivierGrégoire s is an ArrayList, so indexOf will be of generic type T (which is Character for this input list). Apr 20, 2018 at 12:59

# JavaScript, 8580 79 bytes

-6 bytes thanks to @DanielIndie

a=>[...a].sort().map(i=>a.splice(s=a.indexOf(i),1)&&a.splice(a.length-s,0,i))&&a


Try it online!

• this doesnt "compile" a is a string and you use splice Apr 20, 2018 at 7:01
• @DanielIndie Input should be passed as an array of characters, just like Jo King's Python solution. Apr 20, 2018 at 7:21
• 80 bytes Apr 20, 2018 at 7:33
• you dont return anything from that function, or print it Apr 20, 2018 at 7:35
• @DanielIndie Functions can return by modifying their arguments. Apr 20, 2018 at 7:36

# Ruby, 51 bytes

->s{s.sort.map{|c|s.insert~s.index(c),s.delete(c)}}


Try it online!

Takes an array of chars

Returns by modifying the input

# Red, 96 94 bytes

2 bytes saved thanks to Kevin Cruijssen

func[x][foreach c sort copy x[i:(length? x)+ 1 - index? find x c insert at replace x c""i c]x]


Try it online!

f: func[x][
foreach c sort copy x[                  ; for each symbol in the sorted input
i: (length? x) + 1 - index? find x c ; find its index and reflect it
insert at replace x c "" i c         ; remove it by replacing it with an empty char
; and insert the symbol at its new index
]
x                                       ; return the transformed string
]

• You can save 2 bytes by changing find x c replace x c""insert at x i c to find x c insert at replace x c""i c to get rid of an x and space. Apr 20, 2018 at 9:54
• @Kevin Cruijssen Thank you, Kevin, it's much better now! Apr 20, 2018 at 10:30

# R, 7372 69 bytes

function(s){for(x in sort(s))s=append(s[x!=s],x,match(x,rev(s))-1);s}


Try it online!

Inputs and outputs a vector of characters.

• ew, using c as a variable name? that's awful, even for code golf! Apr 20, 2018 at 14:37
• Well, I can obviously change it, but I am really surprised to see that it could bother anybody here. I actually tend to give priority to preserving some sense in variable names (like c for char) rather than unused built-ins. Apr 20, 2018 at 16:19
• well, when looking for an improvement (which, I didn't) I found myself trying to use c, and it was awful when I couldn't figure out what was happening. I typically use K or k or even C just to avoid problems like that, but I totally get it. append is def the right tool for the job. Apr 20, 2018 at 16:26
• Oh, I see, sorry about that, will try to avoid setting such "traps" in future. Apr 20, 2018 at 16:37

# Perl 5-p, 37 bytes

#!/usr/bin/perl -p
for$a(a..z){s/$a//&&s/.{@{-}}$/$a$&/}  Try it online! # Japt, 23 22 bytes ¬n rÈ+S kY iYJ-XbY)x}U ¬n // Split the input into chars and sort it. r }U // Then reduce the result with initial value of the input. È+S // Append a space for replacing edge cases and kY // remove the current char from the string. iY // Insert it back J-XbY // at the calculated index, )x // and remove the unnecessary space once we're done.  Saved one byte thanks to Oliver. Try it online! • Nice one. You can replace ,É with J Apr 20, 2018 at 20:39 • @Oliver Thanks a lot, I still forget to use the default variables every now and then, that's very handy. Apr 22, 2018 at 10:29 ## Haskell, 87 bytes s#c|(h,_:t)<-span(/=c)s,(v,w)<-splitAt(length t)$h++t=v++c:w|1<2=s
f s=foldl(#)s['a'..]


Try it online!

f s=foldl(#)s['a'..]         -- fold the function '#' into all characters from 'a'
-- with the starting value of the input string s
s#c=                          -- in each step (s: result so far, c: next char)
(h,_:t)<-span(/=c)s        -- let 'h' be the substring before 'c' and
-- 't' the substring after 'c'. the pattern match
-- fails if there's no 'c' in 's'
(v,w)<-splitAt(length t)$h++t -- split the string 'h++t' at index length of t =v++c:w -- return 'v' followed by 'c' followed by 'w' |1<2=s -- if there's no 'c' in 's', return 's' unchanged  • Why does this halt? Shouldn't folding over an infinite list cause an infinite loop? Shouldn't it be f s=foldl(#)s['a'..'z']? Apr 20, 2018 at 18:03 • @user1472751: ['a'..] is not infinite, because Char belongs to class Bounded. A list with ..] of Bounded values stops at maxBound. Try: print [False ..]. – nimi Apr 20, 2018 at 18:08 # SNOBOL4 (CSNOBOL4), 132 128 bytes  DEFINE('I(I)') I U =&LCASE N U LEN(1) . K REM . U :F(RETURN) I ARB @S K :F(N) I K = I ARB . L RPOS(S) REM . R I =L K R :(N)  Try it online! Straightforward implementation of the required algorithm. Saved a few bytes by switching to a function rather than a full program; the explanation remains the same, more or less.  I =INPUT ;* read input U =&LCASE ;* alias for lowercase letters (it started out as uppercase) N U LEN(1) . K REM . U :F(O) ;* set K to the next lowercase letter, and when empty, goto O I ARB @S K :F(N) ;* set S to the number of letters before K, or goto N I K = ;* remove K I ARB . L RPOS(S) REM . R ;* set R to the last S characters of I and L to the others I =L K R :(N) ;* recombine the string and goto N O OUTPUT =I ;* print new string END  # Jelly, 12 11 bytes W;ṢḟṁUṣ¥jʋ/  A monadic link accepting a list of characters and returning a list of characters. Try it online! ### How? W;ṢḟṁUṣ¥jʋ/ - Link: list of characters V e.g. "myface" ...i.e. ['m','y','f','a','c','e'] W - wrap V in a list ["myface"] Ṣ - sort V ['a','c','e','f','m','y'] ; - concatenate ["myface",'a','c','e','f','m','y'] / - reduce with: ʋ - last four links as a dyad: - (i.e. start with "myface" on the left and 'a' on the right - 2nd iteration has that result on the left and 'c' on the right - and so-forth) e.g. left = myface, right = 'a' ḟ - filter out (right from left) "myfce" ¥ - last two links as a dyad: U - upend left "ecafym" ṣ - split at occurrences of right ["ec","fym"] ṁ - mould (ḟ(x,y)) like (Uṣ¥(x,y)) ["my","fce"] j - join with right "myafce"  • Ok well this one pretty much wrecks everything else... Apr 20, 2018 at 18:24 • Well I think that's what Jelly is for - I half expect Dennis (Jelly's creator) to submit a shorter one! Apr 20, 2018 at 18:26 • Lol that's pretty amazing :P but I can't upvote b/c I used up my daily vote count..rip Apr 20, 2018 at 18:26 • ...I think there may be a way to save a byte by use of ḟ(filter out) but I have not managed it yet. Apr 20, 2018 at 18:36 • looks like, time-wise, it's O(n log n) in the length of the input since it first uses Python's sorted and then runs through n iterations of what appear to be less complex operations (flattening, splitting at found indices, joining, reversing). -- and Python's sorted is O(n log n). Apr 20, 2018 at 18:41 # C (clang), 164 162 bytes y,n,a,b,c,p,i;f(char*s,l){for(i=0;p=0,++i<123;p<l&&(y=s[p],n=l+~p,a=p+1,b=p,n<p&&(a=n,b=n+1),c=l+~(2*(n<p?n:p)),memmove(s+b,s+a,c),s[n]=y))while(s[p]^i&&p<l)p++;}  Try it online! f() takes char-array containing input string and length of this array as parameters and performs required reflections in place. callf() does pretty-printing. # Credits -2 bytes. @Kevin. Thanks • You can remove the space at char *s and change i=96 to i=9 to save 2 bytes. Apr 20, 2018 at 11:09 • Good catch.. we needn't start from a. Thanks – GPS Apr 20, 2018 at 18:53 • 144 bytes Nov 23, 2018 at 17:23 # APL+WIN, 63 bytes Prompts for input string l←s[⍋⎕av⍳s←,⎕]⋄⍎∊(⍴s)⍴⊂'s←(n←⌽~s=↑l)\s~↑l⋄((~n)/s)←↑l⋄l←1↓l⋄'⋄s  Explanation: l←s[⍋⎕av⍳s←,⎕] sort characters into alphabetical order ⍎∊(⍴s)⍴⊂'....' create an implicit loop for each character s←(n←⌽~s=↑l)\s~↑l⋄((~n)/s)←↑l do the relection for first character in l l←1↓l drop the first character in l s display the result ⋄ statement separator  # Perl, 74 70 bytes 84 80 bytes including invocation as unix filter for$c(a..z){if($p=1+index$_,$c){substr$_,$p-1,1,"";substr$_,-$p,0,$c}}

$echo -e 'dcba\nmyface\na\nacb\ncwmfjordbankglyphsvextquiz' | > perl -pE'for$c(a..z){if($p=1+index$_,$c){substr$_,$p-1,1,"";substr$_,-$p,0,$c}}'
dcba
fyecma
a
bac
ieabhqzugdltkfnvpjxsormycw