28
\$\begingroup\$

Challenge Description

Cycle all letters from the first part of the alphabet in one direction, and letters from the second half of the alphabet in the other. Other characters stay in place.

Examples

1: Hello world

Hello_world //Input
Hell     ld //Letters from first half of alphabet
    o wor   //Letters from second half of alphabet
     _      //Other characters
dHel     ll //Cycle first letters
    w oro   //Cycle second letters
     _      //Other characters stay
dHelw_oroll //Solution

2: codegolf

codegolf
c deg lf
 o   o  

f cde gl
 o   o  

focdeogl

3.: empty string

(empty string) //Input
(empty string) //Output

Input

String you need to rotate. May be empty. Does not contain newlines.

Output

Rotated input string, trailing newline allowed
May be written to the screen or returned by a function.

Rules

  • No loopholes allowed
  • This is code-golf, so shortest code in bytes solving the problem wins
  • Program must return the correct solution
\$\endgroup\$
  • 1
    \$\begingroup\$ Remind me, what letters are from the first half of the alphabet, what letters are from the second? \$\endgroup\$ – user48538 Sep 5 '16 at 14:14
  • \$\begingroup\$ But still, good challenge. \$\endgroup\$ – user48538 Sep 5 '16 at 14:15
  • 4
    \$\begingroup\$ First half: ABCDEFGHIJKLMabcdefghijklm Second half: NOPQRSTUVWXYZnopqrstuvwxyz \$\endgroup\$ – Paul Schmitz Sep 5 '16 at 14:16
  • \$\begingroup\$ Funny that codegolf becomes an anagram of itself \$\endgroup\$ – proud haskeller Sep 6 '16 at 10:51

12 Answers 12

0
\$\begingroup\$

MATL, 29 bytes

FT"ttk2Y213:lM@*+)m)1_@^YS9M(

Try it online!

Explanation

FT        % Push arrray [0 1]
"         % For each
  t       %   Duplicate. Takes input string implicitly in the first iteration
  tk      %   Duplicate and convert to lower case
  2Y2     %   Predefined string: 'ab...yz'
  13:     %   Generate vector [1 2 ... 13]
  lM      %   Push 13 again
  @*      %   Multiply by 0 (first iteration) or 1 (second): gives 0 or 13
  +       %   Add: this leaves [1 2 ... 13] as is in the first iteration and
          %   transforms it into [14 15 ... 26] in the second
  )       %   Index: get those letters from the string 'ab...yz'
  m       %   Ismember: logical index of elements of the input that are in 
          %   that half of the alphabet
  )       %   Apply index to obtain those elements from the input
  1_@^    %   -1 raised to 0 (first iteration) or 1 (second), i.e. 1 or -1
  YS      %   Circular shift by 1 or -1 respectively
  9M      %   Push the logical index of affected input elements again
  (       %   Assign: put the shifted chars in their original positions
          % End for each. Implicitly display
\$\endgroup\$
9
\$\begingroup\$

Retina, 55 bytes

O$i`[a-m](?=.*([a-m]))?
$1
O$i`((?<![n-z].*))?[n-z]
$#1

Try it online!

Uses two sorting stages to rotate the first- and second-half letters separately.

\$\endgroup\$
4
\$\begingroup\$

05AB1E, 44 43 42 bytes

Оn2äø€J2ä©`ŠÃÁUÃÀVv®`yåiY¬?¦VëyåiX¬?¦Uëy?

Explanation

Generate a list of the letters of the alphabet of both cases. ['Aa','Bb', ..., 'Zz']

Оn2äø€J

Split into 2 parts and store a copy in the register.

2ä©

Extract the letters from the input that are a part of the 1st half of the alphabet, rotate it and store in X.

`ŠÃÁU

Extract the letters from the input that are a part of the 2nd half of the alphabet, rotate it and store in Y.

ÃÀV

Main loop

v                         # for each char in input
 ®`                       # push the lists of first and second half of the alphabet
   yåi                    # if current char is part of the 2nd half of the alphabet
      Y¬?                 # push the first char of the rotated letters in Y
         ¦V               # and remove that char from Y
           ëyåi           # else if current char is part of the 1st half of the alphabet
               X¬?        # push the first char of the rotated letters in X
                  ¦U      # and remove that char from X
                    ëy?   # else print the current char

Try it online!

Note: The leading Ð can be omitted in 2sable for a 41 byte solution.

\$\endgroup\$
3
\$\begingroup\$

Javascript (ES6), 155 142 138 bytes

s=>(a=[],b=[],S=s,R=m=>s=s.replace(/[a-z]/gi,c=>(c<'N'|c<'n'&c>'Z'?a:b)[m](c)),R`push`,a.unshift(a.pop(b.push(b.shift()))),s=S,R`shift`,s)

Edit: saved 3 4 bytes by using unshift() (inspired by edc65's answer)

How it works

The R function takes an array method as its parameter m:

R = m => s = s.replace(/[a-z]/gi, c => (c < 'N' | c < 'n' & c > 'Z' ? a : b)[m](c))

It is first used with the push method to store extracted characters in a[] (first half of alphabet) and b[] (second half of alphabet). Once these arrays have been rotated, R() is called a second time with the shift method to inject the new characters in the final string.

Hence the slightly unusual syntax: R`push` and R`shift`.

Demo

let f =
s=>(a=[],b=[],S=s,R=m=>s=s.replace(/[a-z]/gi,c=>(c<'N'|c<'n'&c>'Z'?a:b)[m](c)),R`push`,a.unshift(a.pop(b.push(b.shift()))),s=S,R`shift`,s)

console.log("Hello_world", "=>", f("Hello_world"));
console.log("codegolf", "=>", f("codegolf"));
console.log("HELLO_WORLD", "=>", f("HELLO_WORLD"));

\$\endgroup\$
  • \$\begingroup\$ Save 1 more byte avoiding a comma a.unshift(a.pop(b.push(b.shift()))) \$\endgroup\$ – edc65 Sep 6 '16 at 15:00
2
\$\begingroup\$

CJam, 41 bytes

lee_{'N,_el^:A&},_1m>er_{ADf+&},_1m<erWf=

Try it online!

Uses a similar approach to my vowel shuffling answer.

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

Python, 211 Bytes

x=input()
y=lambda i:'`'<i.lower()<'n'
z=lambda i:'m'<i.lower()<'{'
u=filter(y,x)
d=filter(z,x)
r=l=""
for i in x:
 if y(i):r+=u[-1];u=[i]
 else:r+=i
for i in r[::-1]:
 if z(i):l=d[0]+l;d=[i]
 else:l=i+l
print l

Best i could do. Takes the string from STDIN and prints the result to STDOUT.

alternative with 204 Bytes, but unfortunatly prints a newline after each char:

x=input()
y=lambda i:'`'<i.lower()<'n'
z=lambda i:'m'<i.lower()<'{'
f=filter
u=f(y,x)
d=f(z,x)
r=l=""
for i in x[::-1]:
 if z(i):l=d[0]+l;d=[i]
 else:l=i+l
for i in l:
 a=i
 if y(i):a=u[-1];u=[i]
 print a
\$\endgroup\$
1
\$\begingroup\$

Python 2, 149 bytes

s=input();g=lambda(a,b):lambda c:a<c.lower()<b
for f in g('`n'),g('m{'):
 t='';u=filter(f,s)[-1:]
 for c in s:
  if f(c):c,u=u,c
  t=c+t
 s=t
print s
\$\endgroup\$
  • 2
    \$\begingroup\$ Not sure who downvoted you, but I made it 0 again by upvoting. Welcome to PPCG! Perhaps you could add an explanation or ideone of your code? I'm assuming here that the downvote was done automatically after the edit by Beta Decay by the Community user, based on @Dennis' comment in this answer. \$\endgroup\$ – Kevin Cruijssen Sep 6 '16 at 13:59
1
\$\begingroup\$

JavaScript (ES6), 144

Using parseInt base 36 to separate first half, second half and other. For any character c, I evaluate y=parseInt(c,36) so that

  • c '0'..'9' -> y 0..9
  • c 'a'..'m' or 'A'..'M' -> y 10..22
  • c 'n'..'z' or 'N'..'Z' -> y 23..35
  • c any other -> y NaN

So y=parseInt(c,36), x=(y>22)+(y>9) gives x==1 for first half, x==2 for second half and x==0 for any other (as NaN > any number is false)

First step: the input string is mapped to an array of 0,1 or 2. Meanwhile all the string characters ar added to 3 arrays. At the end of this first step the array 1 and 2 are rotated in opposite directions.

Second step: the mapped array is scanned, rebuilding an output string taking each character from the 3 temporary arrays.

s=>[...s].map(c=>a[y=parseInt(c,36),x=(y>22)+(y>9)].push(c)&&x,a=[[],p=[],q=[]]).map(x=>a[x].shift(),p.unshift(p.pop(q.push(q.shift())))).join``

Less golfed

s=>[...s].map(
  c => a[ y = parseInt(c, 36), x=(y > 22) + (y > 9)].push(c) 
       && x,
  a = [ [], p=[], q=[] ]
).map(
  x => a[x].shift(),  // get the output char from the right temp array
  p.unshift(p.pop()), // rotate p
  q.push(q.shift())   // rotate q opposite direction
).join``

Test

f=
s=>[...s].map(c=>a[y=parseInt(c,36),x=(y>22)+(y>9)].push(c)&&x,a=[[],p=[],q=[]]).map(x=>a[x].shift(),p.unshift(p.pop()),q.push(q.shift())).join``

function update() {
  O.textContent=f(I.value);
}

update()
<input id=I oninput='update()' value='Hello, world'>
<pre id=O></pre>

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

Perl. 53 bytes

Includes +1 for -p

Run with the input on STDIN:

drotate.pl <<< "Hello_world"

drotate.pl:

#!/usr/bin/perl -p
s%[n-z]%(//g,//g)[1]%ieg;@F=/[a-m]/gi;s//$F[-$.--]/g
\$\endgroup\$
0
\$\begingroup\$

Python, 142 133 bytes

A better variation on the theme:

import re
def u(s,p):x=re.split('(?i)([%s])'%p,s);x[1::2]=x[3::2]+x[1:2];return ''.join(x)
v=lambda s:u(u(s[::-1],'A-M')[::-1],'N-Z')

ungolfed:

import re
def u(s,p):
    x = re.split('(?i)([%s])'%p,s)  # split returns a list with matches at the odd indices
    x[1::2] = x[3::2]+x[1:2]
    return ''.join(x)

def v(s):
  w = u(s[::-1],'A-M')
  return u(w[::-1],'N-Z')

prior solution:

import re
def h(s,p):t=re.findall(p,s);t=t[1:]+t[:1];return re.sub(p,lambda _:t.pop(0),s)
f=lambda s:h(h(s[::-1],'[A-Ma-m]')[::-1],'[N-Zn-z]')

ungolfed:

import re
def h(s,p):                              # moves matched letters toward front
    t=re.findall(p,s)                    # find all letters in s that match p
    t=t[1:]+t[:1]                        # shift the matched letters
    return re.sub(p,lambda _:t.pop(0),s) # replace with shifted letter

def f(s):
    t = h(s[::-1],'[A-Ma-m]')            # move first half letters toward end
    u = h(t[::-1],'[N-Zn-z]')            # move 2nd half letters toward front
    return u
\$\endgroup\$
0
\$\begingroup\$

Ruby, 89 bytes

f=->n,q,s{b=s.scan(q).rotate n;s.gsub(q){b.shift}}
puts f[1,/[n-z]/i,f[-1,/[a-m]/i,gets]]
\$\endgroup\$
0
\$\begingroup\$

PHP, 189 bytes

Quite hard to golf... Here is my proposal:

for($p=preg_replace,$b=$p('#[^a-m]#i','',$a=$argv[1]),$i=strlen($b)-1,$b.=$b,$c=$p('#[^n-z]#i','',$a),$c.=$c;($d=$a[$k++])!=='';)echo strpos(z.$b,$d)?$b[$i++]:(strpos(a.$c,$d)?$c[++$j]:$d);
\$\endgroup\$

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.