59
\$\begingroup\$

According to some controversial story, the odrer of ltteres in a wrod deos not mttaer much for raednig, as lnog as the frist and lsat lteter macth with the orignial wrod.

So, for fun, what would be the shortest function to randomize letter order in a word while keeping the first and the last letter in place?

Here's my stab at it with JavaScript. All whitespace removed it's at 124 130 characters.

function r(w) {
  var l=w.length-1;
  return l<3?w:w[0]+w.slice(1,l).split("").sort(function(){return Math.random()-.5}).join("")+w[l];
}

Shorter JavaScript always welcome.


  • Edit: length check added. Function should not fail for short words.
\$\endgroup\$
18
  • 3
    \$\begingroup\$ Haskell, 4 characters: r=id. \$\endgroup\$ Aug 3, 2011 at 20:01
  • 3
    \$\begingroup\$ Yes. It returns the exact same thing as the input. On another note, what do we do about punctuation? Do we only operate on words consisting only of letters? \$\endgroup\$ Aug 3, 2011 at 20:28
  • 1
    \$\begingroup\$ @trinithis not sure what you talking about, but id is the identity function. I would still like to see Haskell solution to this problem in less than 100 characters. \$\endgroup\$
    – Arlen
    Aug 4, 2011 at 7:37
  • 4
    \$\begingroup\$ Should the specification be updated to require a uniform distribution of outcomes? This would disallow the 4 character Haskell solution. It would also disallow your example Javascript solution (shuffling by doing a sort like that is not uniform). \$\endgroup\$ Aug 4, 2011 at 17:25
  • 2
    \$\begingroup\$ +1 for the first sentence: it actually took me a few seconds to realize it was spelled wrong XP \$\endgroup\$ Aug 4, 2011 at 18:33

82 Answers 82

21
\$\begingroup\$

Haskell, 110 120 107 characters

import Random
s l=randomRIO(1,length l-2)>>=g.($l).splitAt
g(a:b,c:d)=fmap(a:).s$c:b++d
g(a,b)=return$a++b

An example of a program using this function:

main = getLine >>= s >>= putStrLn
\$\endgroup\$
3
  • \$\begingroup\$ fmap((a:t!!i:).tail) \$\endgroup\$
    – FUZxxl
    Aug 5, 2011 at 22:00
  • \$\begingroup\$ @FUZxxl, no, sorry, I made the same mistake initially. Operator section does not work here because : is right-associative. I'd have to do (a:).(t!!i:). \$\endgroup\$
    – Rotsor
    Aug 5, 2011 at 22:08
  • \$\begingroup\$ ~3.5 more years of experience, and another 13 characters saved! \$\endgroup\$
    – Rotsor
    Feb 14, 2015 at 21:56
19
\$\begingroup\$

J, 26 24 23 characters

r=:{.,({~?~@#)&}.&}:,{:
\$\endgroup\$
2
  • \$\begingroup\$ According to common code golf rules, you don't have to bind the phrase to a name. \$\endgroup\$
    – FUZxxl
    Feb 14, 2015 at 22:51
  • \$\begingroup\$ #?# is one char shorter than?~@# \$\endgroup\$
    – randomra
    Feb 15, 2015 at 22:11
15
\$\begingroup\$

Ruby, 44 characters

r=->w{w[h=1..-2]=[*w[h].chars].shuffle*"";w}

Works also for short words, i.e. words with one, two or three characters are returned unaltered.

Edit: Using the array-splat idea of Ventero saves another char.

\$\endgroup\$
2
  • \$\begingroup\$ That's actually 44 characters. I eventually came up with the exact same answer by fine tuning my own - now I feel like a copy-cat after reading yours. \$\endgroup\$ Aug 4, 2011 at 8:24
  • \$\begingroup\$ @user2316 Of course you are right. Thank you. \$\endgroup\$
    – Howard
    Aug 4, 2011 at 9:50
11
\$\begingroup\$

Ruby 1.9, 46 characters

r=->w{w[0]+[*w[1..-2].chars].shuffle*""+w[-1]}
\$\endgroup\$
3
  • \$\begingroup\$ +1 This use of array-splat saved me also one char. Great idea. \$\endgroup\$
    – Howard
    Aug 3, 2011 at 16:46
  • \$\begingroup\$ I don't know ruby - it fails on my ruby1.8, so I guess I need a never version? Does it work with input like 'I'? \$\endgroup\$ Aug 4, 2011 at 4:00
  • \$\begingroup\$ @user: It says "Ruby 1.9" right there. ;) -- Ventero - One of the sensible requirements I forgot to mention is that it should not fail for word lengths 0 and 1. Sorry. \$\endgroup\$
    – Tomalak
    Aug 4, 2011 at 6:34
11
\$\begingroup\$

C++, 79 characters (with range check)

string f(string s){if(s.size()>3)random_shuffle(&s[1],&s.end()[-1]);return s;}

C++, 81 65 characters (without range check)

string f(string s){random_shuffle(&s[1],&s.end()[-1]);return s;}

Using pass by reference instead of returning the result shaves off another 10 characters from either solution.

Full program, reading a string of words and shuffling converting them:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <ctime>
#include <string>

using namespace std;    
string f(string s){if(s.size()>3)random_shuffle(&s[1],&s.end()[-1]);return s;}

int main() {
    std::srand(std::time(0));
    std::string s;
    while(std::cin >> s)
        std::cout << f(s) << " ";
    std::cout << std::endl;
}

Morale: don’t build what’s already there. Oh, and overflow checks are for wusses.

\$\endgroup\$
9
  • \$\begingroup\$ Nice, std::random_shuffle, that's a new one to me. btw I think you forgot #include<string> in your full code. \$\endgroup\$ Aug 3, 2011 at 15:48
  • 1
    \$\begingroup\$ Something like that is what I had in mind originally. Unfortunately there is no built-in for shuffling a string in-place in JS. \$\endgroup\$
    – Tomalak
    Aug 3, 2011 at 15:59
  • \$\begingroup\$ Fails for very short strings. \$\endgroup\$ Aug 4, 2011 at 4:02
  • \$\begingroup\$ That's true, you're missing a length check (I did, as well). BTW @Arlen's answer is also worth a look. \$\endgroup\$
    – Tomalak
    Aug 4, 2011 at 6:43
  • 1
    \$\begingroup\$ @userunknown That’s what I meant by “overflow checks are for wusses”. But to be fair, so do almost all other solutions. \$\endgroup\$ Aug 4, 2011 at 7:02
7
\$\begingroup\$

C (K&R) - 88 86 87 chars

r(char*s){int m,j,l=strlen(s)-2,i=l;while(--i>0){j=rand()%l+1;m=s[j];s[j]=s[1];s[1]=m;}}

There's no build-in swap or shuffle function in C, so I had to do it manually :(

Sample Program with Ungolfed r():

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>

// -----------------------------------------------------------------------
r( char *s )
{
    int m, j, l=strlen(s)-2, i=l;

    while (--i>0)
    {
        j = rand() % l + 1;

        m = s[j];
        s[j] = s[1];
        s[1] = m;
    }

}
// -----------------------------------------------------------------------
int main()
{
    char s[] = "anticipated";

    srand( time(0) );
    r( s );
    puts( s );

    return 0;
}

EDIT: fixed the bug when s consists of less than 3 chars (thanks to user-uknown for noticing it! )

\$\endgroup\$
4
  • 1
    \$\begingroup\$ In glibc, there is (was?) a non-standard library function strfry. \$\endgroup\$ Aug 3, 2011 at 23:12
  • \$\begingroup\$ funny experience, if I feed it with char s[] = "na"; // not anticipated \$\endgroup\$ Aug 4, 2011 at 3:30
  • \$\begingroup\$ @user uknown: I just edited the code and fixed it, thanks for noticing the bug! (I just added >0 in the condition of the while loop, "costing me" two more, but needed, chars :) ) \$\endgroup\$
    – Harry K.
    Aug 4, 2011 at 7:53
  • 1
    \$\begingroup\$ @Mechanical snail: I think strfy is still in glibc. \$\endgroup\$
    – Harry K.
    Aug 4, 2011 at 7:56
7
\$\begingroup\$

Python, 87 79 75 93 92 chars

from random import*
f=lambda w:w if 4>len(w)else w[0]+''.join(sample(w[1:-1],len(w)-2))+w[-1]

EDIT: Originally thought it was supposed to split string words (which it did at 128 chars; now at 87 chars does requirement). Argh, my bad at reading comprehension.

EDIT 2: Change from def to lambda function from def to save 6 chars. Assuming sample is already imported to the namespace (from random import sample) could bring this down to ~60).

EDIT 3: "len(w[1:-1])" (12 chars) to "len(w)-2" (8 chars) per gnibbler's nice suggestion.

EDIT 4: JBernando saved one char (had considered from random import * and saw it was equivalent -- not realizing the space in import * is unnecessary).; user unknown added 19 chars w if len(w)<4 else to handle 0 and 1 char strings correctly.

EDIT 5: Saved another char per boothby's code golf trick. if len(w)<4 else to if 4>len(w)else.

\$\endgroup\$
19
  • \$\begingroup\$ However, the question only defined the input as a word, not a string of words. :) \$\endgroup\$ Aug 3, 2011 at 17:10
  • 1
    \$\begingroup\$ @sidran32: Thanks, my bad. I had just noticed (upon rereading) and then saw your comment; deleted -- edited -- and undeleted. \$\endgroup\$
    – dr jimbob
    Aug 3, 2011 at 17:19
  • \$\begingroup\$ Idea - you can trim 3 chars by doing this.... def f(w):j=w[1:-1]; return w[0]+''.join(r.sample(j,len(j)))+w[-1] \$\endgroup\$
    – arrdem
    Aug 3, 2011 at 20:12
  • 4
    \$\begingroup\$ len(w)-2 instead of len(w[1:-1])? \$\endgroup\$
    – gnibbler
    Aug 3, 2011 at 23:29
  • 1
    \$\begingroup\$ from random import* \$\endgroup\$
    – JBernardo
    Aug 4, 2011 at 0:24
6
\$\begingroup\$

C++, 111 97 chars

std::string f(std::string s){for(int i=s.size()-1;i>1;std::swap(s[rand()%i+1],s[--i]));return s;}

Here is a full program for those who wish to test it:

#include<string>
#include<iostream>

std::string f(std::string s){for(int i=s.size()-1;i>1;std::swap(s[rand()%i+1],s[--i]));return s;}

int main(){
    for(int i = 0; i<100; ++i)
    std::cout<<f("letters")<<std::endl;
}

Edit

Realised there is no need to random both swap indexes, saved a variable and a few more characters.

\$\endgroup\$
1
  • \$\begingroup\$ Excellent. Most solutions fail on very small input. Yours not. \$\endgroup\$ Aug 4, 2011 at 4:06
6
\$\begingroup\$

php (68 characters)

$r=preg_replace('/^(\w)(\w+)(\w)$/e','$1.str_shuffle($2).$3',trim($w));

shorter (60 characters)

$r=preg_replace('/(.)(.+)(.)/e','$1.str_shuffle($2).$3',$w);
\$\endgroup\$
3
  • \$\begingroup\$ +1 Very nice. :) You could drop the trim(), actually, and in the regex you can remove the anchors and use . instead of \w. \$\endgroup\$
    – Tomalak
    Aug 3, 2011 at 20:20
  • \$\begingroup\$ @Tomalak Suggested I try rewriting this solution in Perl. Including his suggestions, I got this: use List::Util 'shuffle';sub r{$_[0]=~m/(.)(.+)(.)/;$1.join('',shuffle split//,$2).$3;} That's 87 characters. Without the use line, it's 62 characters. \$\endgroup\$ Aug 3, 2011 at 21:52
  • \$\begingroup\$ Can you provide a demo of this working? Because I can't... \$\endgroup\$ Sep 23, 2011 at 22:33
6
\$\begingroup\$

Perl - 96 (or 71) characters 84 (or 59) characters

This is what I came up with in Perl. Went through a few different ways to do it but this seemed shortest from what I can think of so far, at 97 characters.

use List::Util 'shuffle';sub r{($b,@w)=split//,$_[0];$e=pop(@w);return$b.join('',shuffle@w).$e;}

Though, if you cut out the 'use' line (which I guess is valid, since others excluded #include lines in their C programs) I can cut it down further to 71 characters:

sub r{($b,@w)=split//,$_[0];$e=pop(@w);return$b.join('',shuffle@w).$e;}

EDIT It was suggested that I try doing this implementing @tobius' method. This way I got it down to 84 characters, or by removing the use line, 59 characters:

use List::Util 'shuffle';sub r{$_[0]=~m/(.)(.+)(.)/;$1.join'',shuffle split//,$2.$3}
\$\endgroup\$
5
  • 2
    \$\begingroup\$ shortened your Version down to 87: use List::Util 'shuffle';sub r{($b,@w)=split//,$_[0];$e=pop@w;join'',$b,(shuffle@w),$e} \$\endgroup\$
    – mbx
    Aug 3, 2011 at 18:52
  • 1
    \$\begingroup\$ @sidran32 Can you implement Perl a variant of @tobius' answer, just for comparison? \$\endgroup\$
    – Tomalak
    Aug 3, 2011 at 20:19
  • \$\begingroup\$ @Tomalak Sure, I'll try it out. \$\endgroup\$ Aug 3, 2011 at 21:39
  • 1
    \$\begingroup\$ shortened your regex version down by 3 characters: use List::Util 'shuffle';sub r{$_[0]=~m/(.)(.+)(.)/;$1.join'',shuffle split//,$2.$3} \$\endgroup\$
    – mbx
    Aug 4, 2011 at 9:26
  • \$\begingroup\$ Nice. I'm too used to using a heaping helping of parenthesis for clarity. Bad habit when golfing. :P \$\endgroup\$ Aug 4, 2011 at 18:11
5
\$\begingroup\$

Ruby, 77 75 characters

def r(s);f=s.size-2;1.upto(f){|i|x=rand(f)+1;t=s[i];s[i]=s[x];s[x]=t};s;end

My Scala solution in a slightly less verbose language. I'm not a Ruby expert by any means, so there's probably room for improvement.

\$\endgroup\$
1
  • \$\begingroup\$ Wow. Works with 'I', as your scala solution. \$\endgroup\$ Aug 4, 2011 at 3:35
5
\$\begingroup\$

Ruby 1.9, 77 48 46 44 chars

r=->w{w[h=1..-2]=[*w[h].chars].shuffle*"";w}

Disclaimer: I tuned this based on the highest ranked answer - noticed the exact same answer later on. You can check the history that I have kept true to my original idea but changed from ruby 1.8 to ruby 1.9 for short lambdas and shuffle.

If empty words are allowed then 56 54 chars

r=->w{w.empty?||w[h=1..-2]=[*w[h].chars].shuffle*"";w}
\$\endgroup\$
2
  • \$\begingroup\$ Nobody expects the spanish 'I'. \$\endgroup\$ Aug 4, 2011 at 4:07
  • \$\begingroup\$ Attempted to handle cases with 0 or 1 letters as well \$\endgroup\$ Aug 4, 2011 at 8:14
5
\$\begingroup\$

Python 3, 94 93 91 characters

Using a different technique. Might also work in Python 2.

from random import*
s=lambda x:x[0]+''.join(sample(x[1:-1],len(x)-2))+x[-1]if x[0:-1]else x

The ... if x[0:-1] else x gives x if its length is 1 (otherwise it would be duplicated). The function thereby works for strings of length 0 and 1.

The sample() is from https://stackoverflow.com/questions/2668312/shuffle-string-in-python/2668366#2668366.

Since it's one expression, we can use a lambda (eliminating return, def, and a pair of parentheses).

Edit: from random import* to save 1 character, after the other Python submission.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ I know I am so so so late here, but can x[0:-1] become x[:-1]? \$\endgroup\$
    – Adalynn
    Jul 20, 2017 at 13:22
4
\$\begingroup\$

D, 62 chars

import std.random;void s(char[] s){randomShuffle(s[1..$-1]);}

okay I cheated with a normal char array instead of a real string (which is immutable char[] so no in-place shuffling)

edit with a length check it requires 14 more

import std.random;void s(char[] s){if(s.length>1)randomShuffle(s[1..$-1]);}
\$\endgroup\$
6
  • \$\begingroup\$ And it returns what for an input like 'I'? \$\endgroup\$ Aug 4, 2011 at 3:23
  • \$\begingroup\$ It would be fairer (= better comparable) to return the result. \$\endgroup\$ Aug 4, 2011 at 10:46
  • \$\begingroup\$ @user a range error. @ konrad that would require return s; and char[] return type 11 more chars \$\endgroup\$ Aug 4, 2011 at 13:09
  • \$\begingroup\$ @ratchet Could you post the entire program, please? BTW, I don't understand why you are counting import std.random;, and not just the function. \$\endgroup\$
    – Arlen
    Aug 4, 2011 at 20:11
  • \$\begingroup\$ I'm guessing you could save 1 byte by using omitting the space in char[] s (to make it char[]s), but I haven't used D in years. \$\endgroup\$
    – Tim Čas
    Dec 12, 2016 at 21:42
4
\$\begingroup\$

php 5.3 (60 chars)

$r=!$w[2]?:$w[0].str_shuffle(substr($w,1,-1)).substr($w,-1);

Improved to 56 chars and no longer requires version 5.3:

$r=substr_replace($w,str_shuffle(substr($w,1,-1)),1,-1);
\$\endgroup\$
3
  • \$\begingroup\$ +1 nice alternative to the other PHP answer. Not shorter, but no regex is a plus. \$\endgroup\$
    – Tomalak
    Aug 4, 2011 at 17:30
  • \$\begingroup\$ Updated with a shorter solution that doesn't require version 5.3 \$\endgroup\$
    – migimaru
    Aug 4, 2011 at 18:12
  • \$\begingroup\$ The old version is not correct: returns true for short strings. \$\endgroup\$
    – Titus
    Sep 12, 2016 at 19:15
4
\$\begingroup\$

Python, 86 chars

Slnicig is safe, so no bnouds ckhnceig is neeacrssy. Wkros on all leghtns.

from random import*
def f(x):x=list(x);t=x[1:-1];shuffle(t);x[1:-1]=t;return''.join(x)
\$\endgroup\$
4
\$\begingroup\$

JavaScript - 118 122 125 chars

Uses approximately the same algorithm as the OP, but with less chaining. I tried a lot of recursion, and I tried some iteration, but they all tend to get bogged down in some way or another.

function s(w){w=w.split('');var a=w.shift(),z=w.pop();return z?a+(w.sort(function(){return Math.random()-.5}).join(''))+z:a;}

Ungolfed:

function s(w)
{
    w = w.split('');
    var a = w.shift(),
        z = w.pop();
    return z?a + (w.sort(function() { return Math.random() - .5}).join('')) + z:a;
}
\$\endgroup\$
8
  • \$\begingroup\$ Does not pass the 'I'-test. \$\endgroup\$ Aug 4, 2011 at 3:31
  • \$\begingroup\$ @Ryan Using return z?a+...+z:w; as an implicit length check would be in order. The silent assumption was that the function would receive only "valid" words. \$\endgroup\$
    – Tomalak
    Aug 4, 2011 at 7:06
  • \$\begingroup\$ Good point, except that w has been modified, so I have to use a in the else of the ternary. Edited, and up to 122 chars. \$\endgroup\$
    – Ryan Kinal
    Aug 4, 2011 at 11:57
  • \$\begingroup\$ @Ryan: I believe a would be wrong for two-letter input. :-\ Damn next time I will line out requirements more carefully. \$\endgroup\$
    – Tomalak
    Aug 4, 2011 at 16:40
  • \$\begingroup\$ I don't think it would, actually. z will only be undefined if the word is one letter (or less). \$\endgroup\$
    – Ryan Kinal
    Aug 4, 2011 at 17:02
3
\$\begingroup\$

Perl - 111 characters (without using any library function)

sub r{($f,@w)=split//,shift;$l=pop@w;while(@w){if(rand(9)>1){push@w,shift@w}else{push@t,pop@w}}join'',$f,@t,$l}

Usage:

$in="randomizethis";
$out = &r($in);
print "\nout: $out";
sub r{($f,@w)=split//,shift;$l=pop@w;while(@w){if(rand(9)>1){push@w,shift@w}else{push@t,pop@w}}join'',$f,@t,$l}
\$\endgroup\$
3
\$\begingroup\$

Python

It's 90 89 112 characters of python!

Edit 1: as a function this time!

(thanks gnibbler)

Edit 2: now handles short words

(thanks user unknown)

import random as r
def q(s):
 a=list(s)
 b=a[1:-1]
 r.shuffle(b)
 if len(s)<4:
  return s
 return a[0]+''.join(b)+a[-1]
\$\endgroup\$
5
  • \$\begingroup\$ even less if you follow the spec and write a function :) \$\endgroup\$
    – gnibbler
    Aug 3, 2011 at 23:08
  • \$\begingroup\$ ah, pity shuffle doesn't work on strings \$\endgroup\$
    – gnibbler
    Aug 3, 2011 at 23:28
  • 1
    \$\begingroup\$ The random module is like me at a nightclub... we both just sort of shuffle in place! :) \$\endgroup\$
    – Andbdrew
    Aug 3, 2011 at 23:38
  • \$\begingroup\$ Doesn't work for input like 'I'; return 'II'. \$\endgroup\$ Aug 4, 2011 at 3:24
  • \$\begingroup\$ thanks! it now handles short words, but is slightly longer :) \$\endgroup\$
    – Andbdrew
    Aug 4, 2011 at 12:55
3
\$\begingroup\$

Scala, 135 139 142 156 characters

def r(s:String)={var(x,o,t,f)=(0,s.toArray,' ',s.size-2)
for(i<-1 to f){t=o(i)
x=util.Random.nextInt(f)+1
o(i)=o(x)
o(x)=t}
o.mkString}

-7: removed ':String' (return type can be inferred)
-7: removed 'return ' (last expression is the return value)
-3: factored s.size-2 out
-4: toCharArray -> toArray

\$\endgroup\$
2
  • \$\begingroup\$ Works with 'I' and 'Verwürfel' without fancy Python characters. :) However, my solution using 'shuffle' is a bit shorter. \$\endgroup\$ Aug 4, 2011 at 3:49
  • \$\begingroup\$ @user unknown Thanks for the edits :-) \$\endgroup\$
    – Gareth
    Aug 4, 2011 at 17:27
3
\$\begingroup\$

C++11: - 68 66 chars

auto f=[&](){if(s.size()>2)random_shuffle(s.begin()+1,s.end()-1);};

full program:

#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

int main(int argc, char* argv[]){

  string s = "SomestrinG";
  auto f=[&](){if(s.size()>2)random_shuffle(s.begin()+1,s.end()-1);};

  f();
  cout << s << endl;
  return 0;
}
\$\endgroup\$
2
  • \$\begingroup\$ Is hard coding in the input string legal? \$\endgroup\$ Aug 4, 2011 at 21:38
  • \$\begingroup\$ @trinithis I thought we were only concerned with the function itself. The program only shows how to use the function. Regardless, not hard coding the input would not make a difference in this case; just add string s; cin >> s; \$\endgroup\$
    – Arlen
    Aug 4, 2011 at 21:55
3
\$\begingroup\$

Python - 76 characters

import random as r
def f(w):m=list(w)[1:-1];r.shuffle(m);return w[0]+''.join(m)+w[-1]
\$\endgroup\$
1
3
\$\begingroup\$

R, 104 (126)

f=function(w){s=strsplit(w,"")[[1]];paste(c(s[1],sample(s[2:(length(s)-1)]),s[length(s)]),collapse="")}

Usage:

for (i in 1:10) print(f("parola"))
[1] "plraoa"
[1] "prolaa"
[1] "praola"
[1] "parloa"
[1] "plaora"
[1] "palroa"
[1] "porlaa"
[1] "ploraa"
[1] "porlaa"
[1] "ploraa"

the below function works with words with length less than 3:

f=function(w){s=strsplit(w,"")[[1]];ifelse(length(s)<3,w,paste(c(s[1],sample(s[2:(length(s)-1)]),s[length(s)]),collapse=""))}

f("pl")
[1] "pl"
f("a")
[1] "a"
\$\endgroup\$
4
  • \$\begingroup\$ Part of the task was not to move the first and last letters. \$\endgroup\$
    – Tomalak
    Mar 18, 2012 at 19:15
  • \$\begingroup\$ @Tomalak fixed! \$\endgroup\$
    – Paolo
    Mar 19, 2012 at 8:19
  • \$\begingroup\$ Does it work with words below the length of 3? \$\endgroup\$
    – Tomalak
    Mar 19, 2012 at 8:27
  • \$\begingroup\$ @Tomalak Now it should be ok! Thanks for the corrections! \$\endgroup\$
    – Paolo
    Mar 19, 2012 at 8:48
3
\$\begingroup\$

R, 95 92 91 characters

f=function(w,a=el(strsplit(w,'')),b=length(a))cat(a[1],sample(a[c(1,b)],b-2),a[b],sep="")

Makes use of R's lazy evaluation to compute a and b as function parameters, saving space with re-use later on. Also unlike other R answer this works for all words >1 char long. Example below:

> f("hippopotamus")
hpuoopaitmps

> f("dog")
dog

> f("az")
az

Edit: Replaced unlist() with [[]] Replaced [[1]] with el()

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

D: 55 characters

void f(T)(T s){if(s.length>2)randomShuffle(s[1..$-1]);};

full program:

import std.stdio, std.random, std.conv;

void f(T)(T s){if(s.length>2)randomShuffle(s[1..$-1]);};

void main(){

  char[] s = to!(char[])("SomestrinG");

  f(s);
  writeln(s);
}
\$\endgroup\$
3
  • \$\begingroup\$ I think the else s part is missing? \$\endgroup\$
    – Tomalak
    Aug 5, 2011 at 4:28
  • 1
    \$\begingroup\$ @Tomalak No, it's not, because there is no need for it. If the string is of length 2 or less, then we leave it alone. Also, randomShuffle() is in-place. \$\endgroup\$
    – Arlen
    Aug 5, 2011 at 5:07
  • \$\begingroup\$ Wow, D being competitive. I think randomShuffle(s[1..$-1]) can be s[1..$-1].randomShuffle IIRC (unless that's in a D version older than this post) \$\endgroup\$
    – Adalynn
    Jul 20, 2017 at 13:24
2
\$\begingroup\$

Erlang, 188 172 132 chars

f([H|C=[_|_]])->T=[lists:last(C)],[H|s(C--T,T)];f(X)->X. s([],N)->N;s(D,N)->E=[lists:nth(random:uniform(length(D)),D)],s(D--E,E++N).

I'm still learning Erlang so any tips on making this shorter are appreciated.

full code(string_shuffle module):

-module(string_shuffle).
-export([f/1]).

f([H|C=[_|_]])->
    T=[lists:last(C)],
    [H|s(C--T,T)];f(X)->X.
f(X)->X.

s([],N)->N;
s(D,N)->
    E=[lists:nth(random:uniform(length(D)),D)],
    s(D--E,E++N).

Edit

Took the shuffle part out as a seperate function which no longer requires the head and tail of the list to be passed around.

Edit 2

Restructured to remove one of the ffunction patterns, changed the shuffle function to accept only two parameters, changed lists:delete for --[], swapped a lists:reverse call for a lists:last

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

PowerShell, 93

filter x{if($_.length-lt3){$_}else{$_[0,-1]-join-join($_[1..($a=$_.Length-2)]|random -c $a)}}

Look, double-jointed code!

\$\endgroup\$
4
  • \$\begingroup\$ Way too long, sadly. \$\endgroup\$
    – Joey
    Aug 5, 2011 at 15:56
  • \$\begingroup\$ You can't beat Golfscript anyway. ;) It's way shorter than my JS solution; Powershell is pretty expressive. \$\endgroup\$
    – Tomalak
    Aug 5, 2011 at 16:47
  • \$\begingroup\$ This actually demonstrates plenty of things it doesn't handle well. Usually I aim for at least beating Python :-) \$\endgroup\$
    – Joey
    Aug 6, 2011 at 0:10
  • \$\begingroup\$ saved some bytes by making a var on the first call to .Length and not declaring $a, only -5 thanks to all the brackets needed.. filter x{if(($l=$_.length)-lt3){$_}else{$_[0,-1]-join-join($_[1..($l-2)]|random -c $l)}} \$\endgroup\$
    – colsw
    Dec 6, 2016 at 15:10
2
\$\begingroup\$

C#, 128

static string r(string w){var t="";while(w.Length>1){int n=new Random().Next(1,w.Length-1);t+=w[n];w=w.Remove(n,1);}return w+t;}
\$\endgroup\$
2
\$\begingroup\$

Scala: 94

def r(w:String)=if(w.size<2)w else w(0)+util.Random.shuffle(w.tail.init.toSeq).mkString+w.last

This is a riff on "user unknowns" answer. Since a String can be implicitly cast to a Seq of chars, we can leverage Seq methods to access the middle and end of the String.

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

Groovy, 75

r={w->w.size()<3?w:w[0]+w[1..-2].toList().sort{Math.random()}.join()+w[-1]}

assert r('a') == 'a'
assert r('it') == 'it'
assert r('cap') == 'cap'

for(x in 1..10) {
    def w = r('Honorificabilitudinitatibus')
    println w
    assert w.size()==27 && w[0]=='H' && w[26]=='s'
}
\$\endgroup\$

Your Answer

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

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