10
\$\begingroup\$

You have to write a function/program that takes input via the stdin/command-line arguments/function arguments, mixes up characters in a string, and then output the final string via the stdout.

Input will first contain a string (not empty or null), a space, and then an even number of non-negative numbers all separated by spaces. If input is taken via function arguments, the string will be the one of the arguments while the integers, which are seperated by a space, will be the other. You must swap the characters of the string at the indices corresponding to consecutive pairs of numbers.

For instance:

Hello_world! 0 6

must result in

wello_Horld!

Assumptions

  • You may choose between 0-based and 1-based indexing, and may assume that the given indexes will always be in range.
  • The string will not be longer than 100 characters and will only contain ASCII characters in range ! to ~ (character codes 0x21 to 0x7E, inclusive). See ASCII table for reference.
  • The two indices in a pair may be identical (in which case, nothing is swapped in that step).

Scoring

This is code golf, so the shortest submission (in bytes) wins.

Test Cases

Hello_world! 0 6 => wello_Horld!
First 1 2 1 0 0 4 => tFisr
(Second!$$) 8 7 10 1 => ()econd$!$S
~Third~ 0 0 6 6 0 6 6 0 => ~Third~
\$\endgroup\$
  • 2
    \$\begingroup\$ For future challenges, let me recommend the sandbox where you can get feedback and polish your challenge before posting it on main (this minimises the risk of invalidating existing answers if someone discovers a serious flaw in your challenge that needs fixing). \$\endgroup\$ – Martin Ender May 16 '15 at 12:30
  • \$\begingroup\$ Why require input on stdin, and not, e.g., as command line arguments? \$\endgroup\$ – lrn May 16 '15 at 14:26
  • \$\begingroup\$ @lrn , Right. Added 2 more options. \$\endgroup\$ – Spikatrix May 16 '15 at 15:00
  • \$\begingroup\$ I see a bunch of solutions below that assume that they can get the list of indices as an array that gets passed into the function they implement. The way I read your definition, the input is a single string, which contains the indices as well as the string they operate on, and extracting the indices from the input string is part of the code that needs to be golfed. Can you clarify which interpretation is correct? \$\endgroup\$ – Reto Koradi May 18 '15 at 4:39
  • \$\begingroup\$ @RetoKoradi , No. Input is not a full string. It has a string, and then numbers. The numbers are not included in the string. \$\endgroup\$ – Spikatrix May 18 '15 at 6:48

12 Answers 12

6
\$\begingroup\$

CJam, 11 bytes

rr{irie\r}h

How it works

This is a slightly different approach, in which I simply run a do-while loop till I have pairs of numbers left in the input.

r                 e# Read the first string
 r                e# Read the first number of the first number pair in the input
  {      }h       e# Do a do-while loop
   i              e# Convert the first number from the pair to integer
    ri            e# Read the second number from the pair and convert to intger
      e\          e# String X Y e\ works by swapping the Xth index with the Yth index in the
                  e# String
        r         e# This is our exit condition of the do-while loop. If we still have
                  e# a number on the input left, that means there are more pairs to swap.
                  e# Otherwise, we exit the loop and the result is printed automatically

Try it online here

\$\endgroup\$
6
\$\begingroup\$

Python 3, 89 86 bytes

[*s],*L=input().split()
while L:a,b,*L=map(int,L);s[a],s[b]=s[b],s[a]
print(*s,sep="")

Unpack all the things. (3 bytes saved thanks to @potato)

\$\endgroup\$
  • \$\begingroup\$ Save a few bytes and do this: [*s],*L=input().split() you can then take the line after it away. I really like your solution btw, it's almost elegant even though it is very golfed. \$\endgroup\$ – potato May 17 '15 at 18:40
  • \$\begingroup\$ @potato Oh wow, I didn't know you could have two unpacks together like that (I thought you could only do that in 3.5). Thanks! \$\endgroup\$ – Sp3000 May 18 '15 at 4:04
4
\$\begingroup\$

CJam, 13 bytes

r[q~]2/{~e\}/

Test it here.

Explanation

r             e# Read the first token, i.e. the string.
 [q~]         e# Read the rest of the input, eval it and wrap it in an array.
     2/       e# Split the array into pairs of consecutive elements.
       {   }/ e# For each pair.
        ~     e# Unwrap the array.
         e\   e# Swap the corresponding elements in the string.
\$\endgroup\$
  • \$\begingroup\$ Whoa. Did not expect an answer that fast! \$\endgroup\$ – Spikatrix May 16 '15 at 12:06
2
\$\begingroup\$

C (137 b)

f(char*T,int*V,int L){int C=0;for(int j=0;j<strlen(T);C=++j){for(int i=L-1;i+1;i--)if(C==V[i]){C=V[i-i%2*2+1];i-=i%2;}printf("%c",T[C]);}}

Explanation is coming ...

Arguments

T = a word of type char*.

V = an array of an even number of integer elements.

L = length of V

Output

mixed string

How does it work ?:

sweeps numbers of array V vice versa , and puts the nth element of the string after tracking all its progress until the actual point . Example

input= T="First" , V={1,2,1,0,0,4}

V inversed={4,0,0,1,2,1}

V[0] = 4th element -> index 0
0 -> 1
1->2

4th element 't' receives the second = 'r'

V[1] = 0 -> index 4
4 isnt mentionned after so , no changes

0 element='F' receives the fourth= 't'

V[3] = 1st element -> index 0
no changes

V[4] = 2 -> index 1
no changes after ..

Try it here

\$\endgroup\$
  • 1
    \$\begingroup\$ @Agawa001 , You can golf this a lot more. Return type int is not needed(may result in unexpected behavior), and int variables which are parameters do not need an int, variables, instead of declaring in the loop can be declared in one place outside the loop, use putchar instead of printf etc \$\endgroup\$ – Spikatrix May 17 '15 at 5:15
2
\$\begingroup\$

Python 3 - 161 149

import sys
t=sys.stdin.read().split()
q=list(t[0])
c=1
i=int
while c<len(t):n=q;a=i(t[c]);b=i(t[c+1]);n[a]=q[b];n[b]=q[a];q=n;c+=2;
print(''.join(q))

Golfed more by swapping around some variables, and using ; as in Tim's comment.

I expected it to come out looking golfed, just not this much.

\$\endgroup\$
  • 1
    \$\begingroup\$ You can golf this a lot. Change the while to while c<len(t):line1;line2;line3.... c=c+2 goes to c+=2 \$\endgroup\$ – Tim May 16 '15 at 14:11
  • \$\begingroup\$ @Tim Thanks for your help! \$\endgroup\$ – ASCIIThenANSI May 16 '15 at 14:58
  • \$\begingroup\$ Shouldn't c start at 0? \$\endgroup\$ – Tim May 16 '15 at 14:59
  • \$\begingroup\$ @Tim Nope. c actually is indexing t (the input) to get the positions we need to swap. But since t[0] is the string we need to swap around, t[1] and t[2] hold the first pair of swaps. \$\endgroup\$ – ASCIIThenANSI May 16 '15 at 15:01
  • \$\begingroup\$ Ahh I see, yes. Sorry, my solution split off the input, so i guessed you'd done the same :) \$\endgroup\$ – Tim May 16 '15 at 15:09
2
\$\begingroup\$

C, 109 107 102 bytes

i;f(l){l=sizeof(a)/sizeof(*a);char t;for(;i<l;i+=2){t=s[a[i]];s[a[i]]=s[a[i+1]];s[a[i+1]]=t;}puts(s);}

Note: s and a needs to be declared as global arrays. s is the string which you want to swap and a is an array of int with all the number values.

If the above code does not work, try using void f(){...} instead of f(){...}

Ungolfed code:

int a[]={1, 2, 1, 0, 0, 4};//Integer elements
char s[]="First";          //String to be swapped

i; //Auto initialized to 0 and defaults to type int
void f(l){ //Variables defaults to type int
  l=sizeof(a)/sizeof(*a); //Gets number of elements in array a
  char t;

  for(;i<l;i+=2){ 

    t=s[a[i]];
    s[a[i]]=s[a[i+1]];
    s[a[i+1]]=t;  //Swap each character

  }

  puts(s); //Print the final char array
}

Test it here

\$\endgroup\$
  • \$\begingroup\$ hmm ur code is smaller :) \$\endgroup\$ – Abr001am May 16 '15 at 15:31
  • \$\begingroup\$ lol where is variable declaration ? thats a cheaty way to tighten ur code :p \$\endgroup\$ – Abr001am May 16 '15 at 15:54
  • \$\begingroup\$ @Agawa001 , I didn't include the variable declaration as the bytes would vary with each test case. \$\endgroup\$ – Spikatrix May 17 '15 at 5:06
  • \$\begingroup\$ This does not match the input as defined in the problem. The input is a single string. Unless I completely misunderstood the problem, you need to extract the index values from the input string. \$\endgroup\$ – Reto Koradi May 18 '15 at 4:35
1
\$\begingroup\$

Python 3, 135

x=input().split()
y=list(x[0])
z=[int(i)for i in x[1:]]
while z:p,c=y[z[0]],y[z[1]];y[z[0]],y[z[1]]=c,p;del z[0],z[0]
print(''.join(y))

Explanation:

x=input().split()         # Split the input into a list at each space
y=list(x[0])              # First item in list (the word) into a list of chars
z=[int(i)for i in x[1:]]  # Make the list of numbers, into integers
while z:                  # Loop untill the list z is empty
    p,c=y[z[0]],y[z[1]]   # Assign p to the first char and c to the second
    y[z[0]],y[z[1]]=c,p   # Swap around using p and c
    del z[0],z[0]         # Remove the first 2 items in the list of integers
print(''.join(y))         # Print out the altered list as a string
\$\endgroup\$
1
\$\begingroup\$

C, 70 bytes

Given that the input string is at most length 100 I decided to make the 'NULL' byte indicating the end of the integer array be the unambiguous 0xFF. Presumably this doesn't count as extra input, though for a cost of (at most) 7 3 bytes it can be made into 1-based indexing and use '\0' as the end of the array.

f(s,i,t)char*s,*i;{for(;~*i;)t=s[*i],s[*i]=s[*++i],s[*i++]=t;puts(s);}

Pretty much just does regular swapping with a tmp variable and uses that the comma operator introduces sequence points to have defined behaviour (unlike some manifestations of xor swaps that would have a lower character count but lead to undefined behaviour).

Edit: As requested you can test it out: http://rextester.com/OVOQ23313.

\$\endgroup\$
  • \$\begingroup\$ I don't think you can assume that you get an array with the indices to be swapped. The indices are part of the input string, and you need to parse them out of the string as part of the posted (and counted) code. From the description: "Input will first contain a string, a space, and then an even number of non-negative numbers all separated by spaces." \$\endgroup\$ – Reto Koradi May 18 '15 at 4:27
1
\$\begingroup\$

Dart - 123

Assumes input on the command-line is automatically split at spaces. Otherwise it needs an initial x=x[0].split(' '); to split the string into text and indices.

main(x,{c,i:1,a,t}){c=x[0].split("");n()=>a=int.parse(x[i++]);for(;i<x.length;t=c[n()],c[a]=c[n()],c[a]=t);print(c.join());}

With more whitespace:

main(x,{c,i:1,a,t}){
  c=x[0].split("");
  n()=>a=int.parse(x[i++]);
  for(;i<x.length;t=c[n()],c[a]=c[n()],c[a]=t);
  print(c.join());
}

Run/test this on dartpad.dartlang.org.

\$\endgroup\$
  • \$\begingroup\$ Do you know of any online compilers where I could test this? \$\endgroup\$ – Spikatrix May 17 '15 at 5:12
  • \$\begingroup\$ Add link to DartPad. \$\endgroup\$ – lrn May 17 '15 at 12:32
1
\$\begingroup\$

Rebol - 71

s: take i: split input" "foreach[a b]i[swap at s do a at s do b]print s

Ungolfed:

s: take i: split input " " 
foreach [a b] i [swap at s do a at s do b]
print s
\$\endgroup\$
  • \$\begingroup\$ How do I test this? Is there any online compiler for testing this? \$\endgroup\$ – Spikatrix May 17 '15 at 12:43
  • \$\begingroup\$ @CoolGuy - Yes you can test it at try.rebol.nl The input function won't be able to call STDIN from there. The workaround is to simple set input to be the value you wish to test. Here's full example of the first test - input: "hello_World 1 7" s: take i: split input" "foreach[a b]i[swap at s do a at s do b]print s and click on Do in Rebol 3 NB. Rebol uses 1-based indexing. \$\endgroup\$ – draegtun May 17 '15 at 12:48
  • \$\begingroup\$ @CoolGuy - Alternatively you can download Rebol 3 binaries from rebolsource.net \$\endgroup\$ – draegtun May 17 '15 at 12:51
0
\$\begingroup\$

C, 143 bytes

main(a,v,i)char** v;{i=2;char s[101],t;strcpy(s,v[1]);for(;i<a;i+=2){t=s[atoi(v[i])];s[atoi(v[i])]=s[atoi(v[i+1])];s[atoi(v[i+1])]=t;}puts(s);}

The above program takes input from command-line arguments, copies the string into an array, swaps corresponding characters and then, outputs the modified string.

Ungolfed code:

main(int a,char** v,int i){ //Arguments of main 
  i = 2;
  char s[101],t;

  strcpy(s,v[1]); //Copy string literal into an array

  for(;i<a;i+=2){
    t=s[atoi(v[i])];
    s[atoi(v[i])]=s[atoi(v[i+1])];
    s[atoi(v[i+1])]=t;  //Swap each character
  }

  puts(s); // Output the final string
}
\$\endgroup\$
  • \$\begingroup\$ Are you assuming that the numbers have only one digit? Considering that the input can be up to 100 characters, I don't think that will be valid. Also look at the 3rd example, which has 10 as one of the indices. \$\endgroup\$ – Reto Koradi May 18 '15 at 4:32
  • \$\begingroup\$ @RetoKoradi , Thanks for spotting that. I fixed the code. \$\endgroup\$ – Spikatrix May 18 '15 at 6:06
0
\$\begingroup\$

JavaScript (ES6), 95

95 bytes with a single string input (function f below)

75 bytes with 2 parameters, string and number array (function g below)

(EcmaScript 6, Firefox only)

f=i=>
(
  n=i.split(' '),
  s=[...n.shift()],
  n.map((v,i)=>i&1?[s[v],s[w]]=[s[w],s[v]]:w=v),
  s.join('')
)

g=(s,n)=>
  n.map((v,i)=>i&1?[s[v],s[w]]=[s[w],s[v]]:w=v,s=[...s])
  &&s.join('')

// TEST
out=x=>O.innerHTML+=x+'\n'

;[['Hello_world! 0 6', 'wello_Horld!']
,['First 1 2 1 0 0 4','tFisr']
,['(Second!$$) 8 7 10 1','()econd$!$S']
,['~Third~ 0 0 6 6 0 6 6 0','~Third~']]
.forEach(t=>{
  u=f(t[0]),
  ok=u==t[1],
  out('Test '+(ok?'OK: ':'FAIL: ')+t[0]+'\n Result:' +u + '\n Check: '+t[1]+'\n')
})
<pre id=O></pre>

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