How to randomize letters in a word

55

6

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.

Tomalak

Posted 2011-08-03T11:25:05.427

Reputation: 901

Can we assume that the word is not empty? – Martin Ender – 2015-03-27T16:31:23.040

Throughout the other answers valid results for edge cases ("short input") were required. The empty string qualifies as an edge case, so I'd say no. – Tomalak – 2015-03-27T17:03:46.427

Is there any reason this isn't just as simple as using a built in shuffle function? – Cyoce – 2015-12-27T07:56:30.947

@ThomasEding shuffling arbitrarily long strings uniformly would require that the random number generator has arbitrarily many bits in its state, so id is a good compromise. – Angs – 2016-11-10T19:10:05.807

3Haskell, 4 characters: r=id. – Thomas Eding – 2011-08-03T20:01:53.710

@trinithis Huh? – Tomalak – 2011-08-03T20:11:09.793

The randomizing function always returns the same (AHEM) random outcome. (id x = x is a built in function. For Haskellers out there, I still think id should be able to be written point-free style: id=) – Thomas Eding – 2011-08-03T20:14:10.440

@trinithis I'm afraid I know nothing about Haskell. ;) Does that keep the first and last letters in place? – Tomalak – 2011-08-03T20:24:35.447

2Yes. 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? – Thomas Eding – 2011-08-03T20:28:38.617

@trinithis Yeah I assumed the function would only be fed with valid input, i.e. one word. ;) – Tomalak – 2011-08-03T20:33:36.793

1@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. – Arlen – 2011-08-04T07:37:12.460

To clarify the spec: is it required that the function takes an argument and returns the result or are other solutions acceptable? For instance, in C++ it’s much shorter not to bother with arguments and return type and just mutate some global state. – Konrad Rudolph – 2011-08-04T10:51:08.640

3Should 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). – Thomas Eding – 2011-08-04T17:25:24.497

1I would like to clarify that by uniform, we should treat the problem as if each character was unique. That is, duplicate letters will 'apparently' skew the distribution, but in actuality, it doesn't, because we are really working on the problem of permuting [1, 2, ..., n] while keeping 1 and n in the same spot. – Thomas Eding – 2011-08-04T17:49:52.073

2+1 for the first sentence: it actually took me a few seconds to realize it was spelled wrong XP – Nate Koppenhaver – 2011-08-04T18:33:09.900

Answers

21

Haskell, 4 characters

The function trinithis proposed actually matches the specification:

s=id

It returns the string unchanged, thus keeping the first and last characters in place and doing a permutation of all the other characters.

If someone is dissatisfied with the probability distribution of the permutations, here is a solution yielding a better distribution. It is obviously much more complex:

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

Rotsor

Posted 2011-08-03T11:25:05.427

Reputation: 355

~3.5 more years of experience, and another 13 characters saved! – Rotsor – 2015-02-14T21:56:55.630

4

The first solution should be removed as it does not fit the challenge criteria. The challenge description says "randomize". According to the meta, random cannot always have the same output.

– mbomb007 – 2016-12-06T15:03:09.060

18"dissatisfied with the probability distribution of the permutations" made me laugh. :) – Tomalak – 2011-08-04T16:44:50.837

@Rotsor how do you call that function? – Arlen – 2011-08-04T21:20:22.740

I've added an example to my post. – Rotsor – 2011-08-04T23:46:28.627

fmap((a:t!!i:).tail) – FUZxxl – 2011-08-05T22:00:43.337

@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:). – Rotsor – 2011-08-05T22:08:15.823

19

J, 26 24 23 characters

r=:{.,({~?~@#)&}.&}:,{:

Eric

Posted 2011-08-03T11:25:05.427

Reputation: 291

According to common code golf rules, you don't have to bind the phrase to a name. – FUZxxl – 2015-02-14T22:51:54.787

#?# is one char shorter than?~@# – randomra – 2015-02-15T22:11:23.713

15

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.

Howard

Posted 2011-08-03T11:25:05.427

Reputation: 23 109

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. – Aleksi Yrttiaho – 2011-08-04T08:24:57.610

@user2316 Of course you are right. Thank you. – Howard – 2011-08-04T09:50:52.313

11

Ruby 1.9, 46 characters

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

Ventero

Posted 2011-08-03T11:25:05.427

Reputation: 9 842

+1 This use of array-splat saved me also one char. Great idea. – Howard – 2011-08-03T16:46:37.983

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'? – user unknown – 2011-08-04T04:00:54.250

@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. – Tomalak – 2011-08-04T06:34:50.763

11

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.

Konrad Rudolph

Posted 2011-08-03T11:25:05.427

Reputation: 1 067

-14 bytes for non-range-check version if you use C strings and in-place shuffle: void f(char*s){random_shuffle(s+1,s+strlen(s)-1);}. Another -1 for technically-undefined int instead of void return type (with missing return statement). Might work even without range checks (despite technical UB with <start_of_mem_region>-1) --- I don't know the behavior of random_shuffle if last < first, and it depends on that in that case. – Tim Čas – 2016-12-12T21:36:10.137

Nice, std::random_shuffle, that's a new one to me. btw I think you forgot #include<string> in your full code. – Scott Logan – 2011-08-03T15:48:16.463

1Something like that is what I had in mind originally. Unfortunately there is no built-in for shuffling a string in-place in JS. – Tomalak – 2011-08-03T15:59:46.953

Fails for very short strings. – user unknown – 2011-08-04T04:02:20.160

That's true, you're missing a length check (I did, as well). BTW @Arlen's answer is also worth a look.

– Tomalak – 2011-08-04T06:43:14.077

1@userunknown That’s what I meant by “overflow checks are for wusses”. But to be fair, so do almost all other solutions. – Konrad Rudolph – 2011-08-04T07:02:22.707

At least 1/6 had it right from the start. Lame excuses are for wusses, imho. :) – user unknown – 2011-08-04T10:06:31.967

@user 1/6 isn’t terribly much, and I complied with the OP’s specs. But I’ll change it. – Konrad Rudolph – 2011-08-04T10:30:23.353

Things I've learned: I'll be more careful with the specs next time. That, and there are quite a lot of languages I don't understand the least bit about. – Tomalak – 2011-08-04T16:12:25.607

11

Golfscript

As a "function" (named codeblock): 20 characters

{1/(\)\{;9rand}$\}:r

When operating on the topmost element on the stack: 16 characters

1/(\)\{;9rand}$\

Ventero

Posted 2011-08-03T11:25:05.427

Reputation: 9 842

This fails for single-letter words, and I also don't think that the function should be allowed to return string, array of strings, string (as opposed to a single string). – Martin Ender – 2015-03-27T16:50:12.103

That's not a very good shuffle, but probably OK for this task. (That is, it'll "look random enough".) Still, at the cost of two more chars, you could get a much better shuffle by replacing 9 with 9.?. – Ilmari Karonen – 2012-05-14T20:55:47.593

8

Python, 86 characters

import random as r
def f(w):t=list(w[1:-1]);r.shuffle(t);return w[0]+''.join(t)+w[-1]

And here's an example of using it:

for x in ["ashley", "awesome", "apples"]:
    print f(x)

This is my first code golf exerise. After solving the problem I decided to look at the answers and it's no surprise mine answer isn't unique. This was fun though :o)

I did make one change after looking at the other responses and it was changing my import statement to use an alias. Great idea. ;o)

Ashley Grenon

Posted 2011-08-03T11:25:05.427

Reputation: 181

Fails on short strings; my python answer would be 75 chars if it failed on short strings (from random import*\nf=lambda w:w[0]+''.join(sample(w[1:-1]),len(w)-2)+w[-1]).

– dr jimbob – 2012-03-25T16:39:17.430

And yet, your solution gets voted ahead of mine! :p – boothby – 2011-09-12T19:58:11.607

7

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.

dr jimbob

Posted 2011-08-03T11:25:05.427

Reputation: 336

Lose another two characters with l=len; then 4>l(w) and l(w)-2. – r.e.s. – 2012-03-24T13:55:59.083

@r.e.s. - Don't think that works. l=len; adds 6 chars, and then using l for len twice saves 2 chars twice; meaning its 6-2-2=2 characters longer. – dr jimbob – 2012-03-24T15:44:32.400

Arggg ... that'll teach me to post before having morning coffee. – r.e.s. – 2012-03-25T00:38:01.853

Instead of checking length with if 4>len(w)else you can save some characters by taking advantage of degenerate slice indeces graceful handling: f=lambda w:w[0:1]+''.join(sample(w[1:-1],len(w[1:-1])))+w[1:][-1:] – lortabac – 2012-08-25T10:54:09.847

However, the question only defined the input as a word, not a string of words. :) – Ben Richards – 2011-08-03T17:10:45.720

1@sidran32: Thanks, my bad. I had just noticed (upon rereading) and then saw your comment; deleted -- edited -- and undeleted. – dr jimbob – 2011-08-03T17:19:29.827

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] – arrdem – 2011-08-03T20:12:42.507

@rmckenzie: Good idea. However, right before I saw your comment right after I trimmed it to lambda function (saving 6 chars), so I can no longer do your method of defining intermediate vars. – dr jimbob – 2011-08-03T20:20:28.297

3len(w)-2 instead of len(w[1:-1])? – gnibbler – 2011-08-03T23:29:58.110

@gnibbler - thanks. Saved 4 chars. Now its 75 characters (or 51 if sample has already been imported and we don't assign the lambda function to anything) lambda w:w[0]+''.join(sample(w[1:-1],len(w)-2))+w[-1] – dr jimbob – 2011-08-04T00:13:09.087

from random import* – JBernardo – 2011-08-04T00:24:32.603

Fails on words like 'I'. – user unknown – 2011-08-04T03:54:56.313

@user unknown - Not too difficult to handle short strings correctly (if input less than 4 characters just return the original string). Adds 19 chars -- change the second line to f=lambda w:w if len(w)<4 else w[0]+''.join(r.sample(w[1:-1],len(w)-2)+w[-1] will handle that case. However, it wasn't clear from the description if short strings should be handled correctly -- the example code clearly does not handle zero/one character strings correctly (in the example code - r('') gives 'undefinedundefined' and r('I') gives 'II'). – dr jimbob – 2011-08-04T05:09:21.750

Since tomalak seemed to use his function for the question (in a wrod), I thought his example is all right. He must have stumbled over this problem, or he feed his words by hand to the function, only choosing words of size 4 or more. However - to me it seems clear, that such a function would be used to work on sentences or wordlists, and should be a little robust. – user unknown – 2011-08-04T05:19:53.057

@user: Actually, I scrambled the words manually. Unbelievable, but true. ;) Anyway, since defining what "a word" is and how to handle sentences would have been too much noise, I assumed that proper tokenization would take place elsewhere. Your hint that word length should be 4 or more characters is noted. I'll change my own implementation. – Tomalak – 2011-08-04T06:21:39.120

Save another character with if 4>len(w)else. – boothby – 2011-08-04T20:15:07.143

Isn't this 94 characters? – Mechanical snail – 2011-08-05T02:05:38.530

@Mechanical snail; I made a mistake -- but I think its 92 now. My mistake was len('from random import*')+len('f=lambda w:w if 4>len(w)else w[0]+''.join(sample(w[1:-1],len(w)-2))+w[-1]') which I now realize undercounted by 2 (as it took at as two string concatenated together as I used single quotes twice in the second len). I noticed that after removing one letter it shot down by 3; and figured I had counted incorrectly earlier see edit history. Are new lines generally counted as a character in golf? If yes, that would make it 93 now (94 if new line is counted as 2 chars like '\n'). – dr jimbob – 2011-08-05T02:54:03.543

Necessary whitespace generally should be one char each, not counting EOF. – cemper93 – 2011-08-11T15:33:08.597

7

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! )

Harry K.

Posted 2011-08-03T11:25:05.427

Reputation: 215

1In glibc, there is (was?) a non-standard library function strfry. – Mechanical snail – 2011-08-03T23:12:41.057

funny experience, if I feed it with char s[] = "na"; // not anticipated – user unknown – 2011-08-04T03:30:10.967

@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 :) ) – Harry K. – 2011-08-04T07:53:05.797

1@Mechanical snail: I think strfy is still in glibc. – Harry K. – 2011-08-04T07:56:15.153

6

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.

Scott Logan

Posted 2011-08-03T11:25:05.427

Reputation: 332

Excellent. Most solutions fail on very small input. Yours not. – user unknown – 2011-08-04T04:06:17.537

6

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}

Ben Richards

Posted 2011-08-03T11:25:05.427

Reputation: 291

2shortened your Version down to 87: use List::Util 'shuffle';sub r{($b,@w)=split//,$_[0];$e=pop@w;join'',$b,(shuffle@w),$e} – mbx – 2011-08-03T18:52:21.323

1

@sidran32 Can you implement Perl a variant of @tobius' answer, just for comparison?

– Tomalak – 2011-08-03T20:19:24.873

@Tomalak Sure, I'll try it out. – Ben Richards – 2011-08-03T21:39:44.577

1shortened your regex version down by 3 characters: use List::Util 'shuffle';sub r{$_[0]=~m/(.)(.+)(.)/;$1.join'',shuffle split//,$2.$3} – mbx – 2011-08-04T09:26:23.253

Nice. I'm too used to using a heaping helping of parenthesis for clarity. Bad habit when golfing. :P – Ben Richards – 2011-08-04T18:11:12.370

6

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);

tobius

Posted 2011-08-03T11:25:05.427

Reputation: 161

+1 Very nice. :) You could drop the trim(), actually, and in the regex you can remove the anchors and use . instead of \w. – Tomalak – 2011-08-03T20:20:52.563

@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. – Ben Richards – 2011-08-03T21:52:28.387

Can you provide a demo of this working? Because I can't... – Steve Robbins – 2011-09-23T22:33:07.457

5

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}

Aleksi Yrttiaho

Posted 2011-08-03T11:25:05.427

Reputation: 181

Nobody expects the spanish 'I'. – user unknown – 2011-08-04T04:07:49.623

Attempted to handle cases with 0 or 1 letters as well – Aleksi Yrttiaho – 2011-08-04T08:14:38.507

5

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.

Gareth

Posted 2011-08-03T11:25:05.427

Reputation: 11 678

Wow. Works with 'I', as your scala solution. – user unknown – 2011-08-04T03:35:19.917

5

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.

Mechanical snail

Posted 2011-08-03T11:25:05.427

Reputation: 2 213

1I know I am so so so late here, but can x[0:-1] become x[:-1]? – Zacharý – 2017-07-20T13:22:51.563

4

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;
}

Ryan Kinal

Posted 2011-08-03T11:25:05.427

Reputation: 141

@userunknown What's that? – BadHorsie – 2015-03-31T11:27:56.987

@BadHorsie: I don't remember. A Test with a one letter word? – user unknown – 2015-03-31T19:14:37.330

Does not pass the 'I'-test. – user unknown – 2011-08-04T03:31:17.237

@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. – Tomalak – 2011-08-04T07:06:37.943

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. – Ryan Kinal – 2011-08-04T11:57:51.530

@Ryan: I believe a would be wrong for two-letter input. :-\ Damn next time I will line out requirements more carefully. – Tomalak – 2011-08-04T16:40:03.210

I don't think it would, actually. z will only be undefined if the word is one letter (or less). – Ryan Kinal – 2011-08-04T17:02:44.007

For what it's worth, the distribution of outcomes your function creates is not uniform: w.sort(function() { return Math.random() - .5}) is the culprit, yeilding the skewed distribution. – Thomas Eding – 2011-08-04T17:24:00.317

4

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]);}

ratchet freak

Posted 2011-08-03T11:25:05.427

Reputation: 1 334

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. – Tim Čas – 2016-12-12T21:42:52.977

Yeah. char[] s=>char[]s and randomShuffle(s[1..$-1]) => s[1..$-1].randomShuffle. Wow, two D answers. – Zacharý – 2017-07-20T13:27:04.957

And it returns what for an input like 'I'? – user unknown – 2011-08-04T03:23:40.507

It would be fairer (= better comparable) to return the result. – Konrad Rudolph – 2011-08-04T10:46:23.120

@user a range error. @ konrad that would require return s; and char[] return type 11 more chars – ratchet freak – 2011-08-04T13:09:12.857

@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. – Arlen – 2011-08-04T20:11:18.413

4

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);

migimaru

Posted 2011-08-03T11:25:05.427

Reputation: 1 040

The old version is not correct: returns true for short strings. – Titus – 2016-09-12T19:15:18.753

+1 nice alternative to the other PHP answer. Not shorter, but no regex is a plus. – Tomalak – 2011-08-04T17:30:06.227

Updated with a shorter solution that doesn't require version 5.3 – migimaru – 2011-08-04T18:12:34.243

4

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)

boothby

Posted 2011-08-03T11:25:05.427

Reputation: 9 038

3

Python, 102 characters

def f(x):t=list(x)[1:-1];k='';exec'k+=t.pop(id(7)%len(t));'*len(t);return[x[0],x[0]+k+x[-1]][len(x)>1]

No imports! Works for words 1 character and above. This is my first golf entry and I was inspired by BlueEyedBeast's entry from Shortest code to produce non-deterministic output for the idea of using id(Object).


Explanation: It makes a list of letters from the input excluding the first and last, and repeatedly pops from this list and appends to a new one until empty. The index it pops from is id(7) % len(list we're popping from). Since id(7) is the memory address of the object 7, it is essentially random. So now we have a list of randomly scrambled letters from the center of the original input. All we do now is append the first and last letters of the original output accordingly and we got the output we want: (first letter)+(scrambled middle)+(last letter).

giraffe

Posted 2011-08-03T11:25:05.427

Reputation: 31

3

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()

Andrew Haynes

Posted 2011-08-03T11:25:05.427

Reputation: 311

3

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

Gareth

Posted 2011-08-03T11:25:05.427

Reputation: 11 678

Works with 'I' and 'Verwürfel' without fancy Python characters. :) However, my solution using 'shuffle' is a bit shorter. – user unknown – 2011-08-04T03:49:56.833

@user unknown Thanks for the edits :-) – Gareth – 2011-08-04T17:27:05.260

3

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}

mbx

Posted 2011-08-03T11:25:05.427

Reputation: 149

3

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]

Andbdrew

Posted 2011-08-03T11:25:05.427

Reputation: 221

even less if you follow the spec and write a function :) – gnibbler – 2011-08-03T23:08:20.623

ah, pity shuffle doesn't work on strings – gnibbler – 2011-08-03T23:28:40.327

1The random module is like me at a nightclub... we both just sort of shuffle in place! :) – Andbdrew – 2011-08-03T23:38:29.180

Doesn't work for input like 'I'; return 'II'. – user unknown – 2011-08-04T03:24:40.037

thanks! it now handles short words, but is slightly longer :) – Andbdrew – 2011-08-04T12:55:05.820

3

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;
}

Arlen

Posted 2011-08-03T11:25:05.427

Reputation: 181

Is hard coding in the input string legal? – Thomas Eding – 2011-08-04T21:38:06.683

@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; – Arlen – 2011-08-04T21:55:28.043

3

Ruby 1.9, 43 characters

r=w[0]+[*w[1..-2].chars].shuffle.join+w[-1]

Does not yet work for 1 character length Strings (duplicates that character), and fails for empty String.

karatedog

Posted 2011-08-03T11:25:05.427

Reputation: 131

3

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]

Donald Wilson

Posted 2011-08-03T11:25:05.427

Reputation: 31

George's userscript puts this at 85 characters. – dmckee --- ex-moderator kitten – 2011-09-10T00:14:21.163

3

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"

Paolo

Posted 2011-08-03T11:25:05.427

Reputation: 696

Part of the task was not to move the first and last letters. – Tomalak – 2012-03-18T19:15:38.023

@Tomalak fixed! – Paolo – 2012-03-19T08:19:41.123

Does it work with words below the length of 3? – Tomalak – 2012-03-19T08:27:54.490

@Tomalak Now it should be ok! Thanks for the corrections! – Paolo – 2012-03-19T08:48:53.130

2

Perl, 41 bytes

40 bytes code + 1 for -n.

$\=chop;s/.//;print"$&",sort{rand 2}/./g

Requires input to be supplied without a newline (echo -n ...) as we use chop to move the last char into $\ (which is appended after all arguments to print) and we sort, applying 0 or 1 (rand 2) to each character. This appears to result in all permutations given enough time. The $& has to be in quotes, as it changes after the /./g is executed, interpolating into a string works around this. Also print has to be used instead of say to utilise $\ :(.

Usage

echo -n 'stringified' | perl -ne '$\=chop;s/.//;print"$&",sort{rand 2}/./g'
sifirgtined

for i in `seq 1 20`; do echo -n 'stringified' | perl -ne '$\=chop;s/.//;print"$&",sort{rand 2}/./g'; echo; done 
segfiiintrd
sitnrigfied
stringified
srtinigfied
sginitrefid
strnigieifd
seriftniigd
sifertniigd
siirtngfied
sintrgieifd
snitrigefid
sfgieinirtd
sigitrnifed
sefiirtingd
sirtnigifed
sifgenritid
srtingiifed
siignrteifd
sefiigtrind
sifneirtigd

Dom Hastings

Posted 2011-08-03T11:25:05.427

Reputation: 16 415

2

Taxi, 1344 bytes

Go to Post Office:w 1 l 1 r 1 l.Pickup a passenger going to Chop Suey.Go to Chop Suey:n 1 r 1 l 4 r 1 l.Pickup a passenger going to Post Office.[B]Switch to plan C if no one is waiting.Pickup a passenger going to Cyclone.Go to Cyclone:n 1 l 3 l.Pickup a passenger going to Narrow Path Park.Pickup a passenger going to Sunny Skies Park.Go to Zoom Zoom:n.Go to Sunny Skies Park:w 2 l.Go to Narrow Path Park:n 1 r 1 r 1 l 1 r.Go to Chop Suey:e 1 r 1 l 1 r.Switch to plan B.[C]Go to Narrow Path Park:n 1 l 1 r 1 l.Switch to plan H if no one is waiting.Pickup a passenger going to Joyless Park.Go to Joyless Park:e 1 r 3 l.Go to Narrow Path Park:w 1 r 3 l.[D]Switch to plan E if no one is waiting.Pickup a passenger going to Cyclone.Go to Cyclone:w 1 l 1 r 2 l.Pickup a passenger going to Firemouth Grill.Pickup a passenger going to Sunny Skies Park.Go to Zoom Zoom:n.Go to Firemouth Grill:w 1 l 2 r 3 r.Go to Sunny Skies Park:w 1 l 1 r 1 r.Go to Narrow Path Park:n 1 r 1 r 1 l 1 r.Switch to plan D.[E]Go to Firemouth Grill:e 1 r 4 r.[F]Switch to plan G if no one is waiting.Pickup a passenger going to Post Office.Go to Fueler Up:e 1 l.Go to Post Office:s 1 r 1 l.Go to Firemouth Grill:n 1 l.Switch to plan F.[G]Go to Joyless Park:e 1 l 3 r.Pickup a passenger going to Post Office.Go to Post Office:w 1 l 1 r 1 l.[H]Go to Post Office:e 1 r 4 r 1 l.

Try it online!

Try it online with linebreaks!

Errors out by having the boss fire me if the string is 1 character, and by being unable to drive in the current direction otherwise. Don't you just love programs that exit uncleanly like that?

Firemouth Grill is one of two destinations in Townsville that offer randomness. It is like any of the three parks in that any number of passengers can be dropped off for later, but they are picked up in a random and unspecified order. This destination alone does the main part of our job, so the only other thing to do is make sure we're only doing this to the characters in the middle.

JosiahRyanW

Posted 2011-08-03T11:25:05.427

Reputation: 2 600

1This is amazing :D – Tomalak – 2018-10-09T07:24:11.393

2

Powershell, 81 bytes

Inspired by Joey: I like her double join.

$args|%{($_,($_[0,-1]-join-join($_[1..($a=$_.Length-2)]|random -c 2e9)))[$a-ge2]}

Notable changes:

  1. if else replaced with a Fake ternary operator.
  2. $_.Length is written once.
  3. Other golf to compact the script
  4. The script gets Random for the word length >= 4 only.
  5. random -c $a replaced with random -c 2e9. It need to avoid an exception with word length <= 2. I think the length = 2000000000 is enough for a word.

Test script:

$f = {

$args|%{($_,($_[0,-1]-join-join($_[1..($a=$_.Length-2)]|random -c 2e9)))[$a-ge2]}

}

&$f ""
&$f a
&$f ab
&$f abc
&$f abcd
&$f randomize
&$f reading
&$f Hello
&$f world

Output:

a
ab
abc
acbd
rmaniodze
rniedag
Hlelo
wrlod

mazzy

Posted 2011-08-03T11:25:05.427

Reputation: 4 832

2

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

Scott Logan

Posted 2011-08-03T11:25:05.427

Reputation: 332

2

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);
}

Arlen

Posted 2011-08-03T11:25:05.427

Reputation: 181

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) – Zacharý – 2017-07-20T13:24:27.400

I think the else s part is missing? – Tomalak – 2011-08-05T04:28:30.317

1@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. – Arlen – 2011-08-05T05:07:46.923

2

PowerShell, 93

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

Look, double-jointed code!

Joey

Posted 2011-08-03T11:25:05.427

Reputation: 12 260

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)}} – colsw – 2016-12-06T15:10:06.987

Way too long, sadly. – Joey – 2011-08-05T15:56:27.670

You can't beat Golfscript anyway. ;) It's way shorter than my JS solution; Powershell is pretty expressive. – Tomalak – 2011-08-05T16:47:38.557

This actually demonstrates plenty of things it doesn't handle well. Usually I aim for at least beating Python :-) – Joey – 2011-08-06T00:10:58.633

2

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;}

Luis SaTaNiC

Posted 2011-08-03T11:25:05.427

Reputation: 21

2

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.

bkuder

Posted 2011-08-03T11:25:05.427

Reputation: 51

2

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'
}

Armand

Posted 2011-08-03T11:25:05.427

Reputation: 499

2

CJam, 15 bytes

CJam is younger than this challenge, so this submission is not eligible for being accepted. This submission assumes that a "word" contains at least one character (I've requested clarification from the OP).

{(\_W>\W<mr\++}

This defines a block, the equivalent of an unnamed function in CJam.

Test it here.

If full programs (STDIN to STDOUT) are also acceptable, it can be solved in 12 bytes:

l(\_W>\W<mr\

Test it here.

Explanation

(             "Slice off first character and push it on the stack.";
 \            "Swap with remaining string.";
  _W>         "Duplicate and truncate to last character.";
     \W<      "Swap with other copy and slice off last character.";
        mr    "Shuffle.";
          \   "Swap with last character.";
           ++ "Concatenate the three parts back together.";

Note that _W>\W< could in principle be shortened to )\ (which I had originally). However, this fails when the string is empty at that point, i.e. when it originally contained less than 2 characters.

For the full program, we read the input with l first, and we can omit the ++ since the contents of the stack are printed at the end of the program automatically, back to back.

Martin Ender

Posted 2011-08-03T11:25:05.427

Reputation: 184 808

This is amazing :) – Tomalak – 2015-03-27T16:08:30.353

2

Q, 38 48

{((:)x),((-1(#:)a)?a:-1_1_x),last x}

Had to change it for words <=3 letters

{$[3<(#)x;((*:)x),((-1*(#:)a)?a:-1_1_x),-1#x;x]}

tmartin

Posted 2011-08-03T11:25:05.427

Reputation: 3 917

You can get three less along the same vein: {$[3<(#)x;(1#x),((-1*(#)a)?a:-1_1_x),-1#x;x]} – skeevey – 2012-03-20T21:03:25.250

2

MATLAB (46 Characters)

f=@(x)[x(1) x(randperm(length(x)-2)+1) x(end)]

Sample Usage:

>> f('elephant')

ans =

eplhnaet

>> f('imawesomebutyousuck')

ans =

iouesutuoeswbamycmk

Works with words size two or greater.

jazzkingrt

Posted 2011-08-03T11:25:05.427

Reputation: 21

2

Python 3, 80 chars

This is an improvement on Ashley Grenon's answer. By removing variable assignments and using random.sample instead of random.shuffle, so you don't have to explicitly call list(), I saved 4 characters. This one still fails on strings less than 2 characters.

import random as r
def f(w):return w[0]+''.join(r.sample(w[1:-1],len(w)-2))+w[-1]

dzil123

Posted 2011-08-03T11:25:05.427

Reputation: 21

Welcome to Programming Puzzles and Code Golf. This is a great answer; much better than the average first post. If you feel it is required, adding a code breakdown and explanation may improve this answer. – wizzwizz4 – 2015-12-27T11:18:19.543

2

APL (Dyalog), 34 Charachters

Still trying to golf it a bit more, new to APL. Tips appreciated.

y←(⍴x←⍞)-2⋄x[1],x[1+⍳y][y?y],x[⍴x]

Here is an attempt to explain it, I also simplified it a bit (no charachter improvement, though)

is a statement separator, think of it as a new line.

That leaves us with 2 statements. y←(⍴x←⍞)-2 and x[1],x[1+⍳y][y?y],x[⍴x]

APL works from right to left in statements, but follows parentesis still, so (⍴x←⍞) is executed first. takes charachter input. assigns that to x and gives the length of x. Then the -2 is executed, which subtracts 2 from the length of x. Finally, the length-2 is assigned to y and we move on to the next statement.

x[⍴x] takes the last character of x, think of it as x[x.length] (using the length as the index of the last character).

, is catenate.

So we concatenate the last character of x with x[1+⍳y][y?y] which takes the middle indices of x using 2+⍳y and applies a randomization using [y?y].

⍳y generates 1 2 3 ... y and 1+ turns this into 2 3 4 ... y+1 which are the middle indices of x, for example, this returns bcdef from abcdefg.

[y?y] "deals" y values from 1 to y.

So, x[1+⍳y][y?y] grabs the middle of the word and randomizes it.

Finally, we concatenate the first charachter of x using x[1], to the rest of the string, and that is the output of the program.

Hopefully that was understandable...

MrZander

Posted 2011-08-03T11:25:05.427

Reputation: 871

1Oh dear God. (+1) -- Would you care to break it down for somebody who has no concept of APL? – Tomalak – 2012-08-23T05:43:59.923

Sure, give me a minute to update it – MrZander – 2012-08-23T05:49:51.097

No problem. If you can "golf it down" more do that first. – Tomalak – 2012-08-23T05:52:00.690

@Tomalak explained it as best as I could :) – MrZander – 2012-08-23T06:08:30.510

2

J, 25

(]/:0,((2-~#)?1-~#),1-~#)

Example:

      (]/:0,((2-~#)?1-~#),1-~#) 'order'
oedrr
      (]/:0,((2-~#)?1-~#),1-~#) 'order'
oerdr
      (]/:0,((2-~#)?1-~#),1-~#) 'order'
oderr
      (]/:0,((2-~#)?1-~#),1-~#) 'order'
odrer
      (]/:0,((2-~#)?1-~#),1-~#) 'order'
oerdr
      (]/:0,((2-~#)?1-~#),1-~#) 'order'
oerdr

defhlt

Posted 2011-08-03T11:25:05.427

Reputation: 1 717

I can get down to 22 using the random shuffle verb on this page.

– Gareth – 2012-08-23T12:02:02.957

Actually ignore my last comment, the top answer uses the method I would have used. – Gareth – 2012-08-23T13:00:41.520

2

Ruby, 39 characters

->s{a,*b,c=s.chars;[a,*b.shuffle,c]*''}

Lee W

Posted 2011-08-03T11:25:05.427

Reputation: 521

You supposed to process each word of the input text separately. – manatwork – 2016-11-10T19:34:42.157

2@manatwork The reference solution clearly assumes that the input is a single word. I'm certain that this is what the author intended. – Lee W – 2016-11-10T19:42:32.980

Oops. I misread its .split(""). You are right. Sorry. Confused it with Cambridge Transposition.

– manatwork – 2016-11-10T20:33:37.447

1

Coffee-script: 76 91 Bytes

f=(a)->a.length>1&&a[0]+(a.split('')[1..-2].sort ()->.5-Math.random()).join('')+a[-1..]||a

Wow, I like this language already.

Lord Ratte

Posted 2011-08-03T11:25:05.427

Reputation: 111

1

><>, 40 bytes

_5l)?vl1-[&r02.
} .32<
x{|$!
/r]&
>l?!;o

Try it here!

redstarcoder

Posted 2011-08-03T11:25:05.427

Reputation: 1 771

1

PHP 7.1, 54 bytes

If the word has less than 4 letters, don´t shuffle:

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

Titus

Posted 2011-08-03T11:25:05.427

Reputation: 13 814

1

><>, 19 bytes

{o&v
?vo>xl2(
&<oo{

Try it online!

Works for words of less than 3 length.

Jo King

Posted 2011-08-03T11:25:05.427

Reputation: 38 234

1

R, 93 79 bytes

function(x,l=nchar(x))"if"(l<4,x,intToUtf8(utf8ToInt(x)[c(1,sample(l-2)+1,l)]))

Try it online!

Wroks for any ipnut szie dwon to zero, by frsit ckciheng the lgnteh of the sintrg and rneturing it if nchar(x)<4

-14 bytes thanks to Giuseppe!

JayCe

Posted 2011-08-03T11:25:05.427

Reputation: 2 655

89 bytes changing the sampling a bit – Giuseppe – 2018-07-17T20:40:31.560

Oops, 83 bytes

– Giuseppe – 2018-07-17T20:41:51.673

Aaaand another one for good measure: 79 bytes -- in all fairness to me, I haven't gotten much sleep the last few days.

– Giuseppe – 2018-07-17T20:48:50.720

@Giuseppe This is much better indeed! – JayCe – 2018-07-18T00:23:38.717

1

JavaScript, 102 bytes

(_,a=[..._].slice(1,-1))=>_.replace(/./g,(m,i)=>(l=a.length,!i||!l?m:a.splice(~~(Math.random()*l),1)))

Try it online!

Using spread syntax and .slice() create array from input string beginning at index 1 through -1, .splice() elements from array within .replace() callback function, return string.

guest271314

Posted 2011-08-03T11:25:05.427

Reputation: 1

1

APL(NARS), 52 chars, 104 bytes

∇r←s w;x
r←,w⋄→0×⍳3≥⍴w⋄r←(↑w),x[?⍨⍴x←¯1↓1↓w],¯1↑w
∇

This 'solution' is based to the fact that 3?3 return a random permutation of 1 2 3;
6?6 a random permutation of 1 2 3 4 5 6 ecc n?n a random permutation of 1 2 .. n so if B is a string B[(⍴B)?⍴B] would be a string random permutation of B. The function 's' has to have as input one string and return one string or ''. If someone see some error, please to say, thank you.

test:

  ⎕fmt s¨'' 'w' 'my' 'the' 'this' 'this' 'this'
┌7────────────────────────────────────────────┐
│┌0┐ ┌1─┐ ┌2──┐ ┌3───┐ ┌4────┐ ┌4────┐ ┌4────┐│
││ │ │ w│ │ my│ │ the│ │ tihs│ │ this│ │ this││
│└¯┘ └──┘ └───┘ └────┘ └─────┘ └─────┘ └─────┘2
└∊────────────────────────────────────────────┘
  s¨'random' 'random' 'random' 'random'
rdonam rodanm raodnm rodnam 
  s 'permutation'
ptaemutroin

RosLuP

Posted 2011-08-03T11:25:05.427

Reputation: 3 036

1

C# w/Linq - 152 non-whitespace chars.

It's terrible compared to other languages on char count, but elegant:

public string Shuf(string i)
{
    return new String(i.Take(1)
        .Concat(i.Skip(1).Take(i.Length-2).OrderBy(x=>Guid.NewGuid()))
        .Concat(new[]{i.Last()})
        .ToArray());
}

KeithS

Posted 2011-08-03T11:25:05.427

Reputation: 211

there's no Rand class in C# - it's Random. Also, name the function S instead of Shuf to gain some chars. – Cristian Lupascu – 2012-05-15T07:06:53.140

also, for a reason I haven't discovered yet, x=>new Random().Next() does not actually randomize the string. Try _=>Guid.NewGuid() - it's shorter and works – Cristian Lupascu – 2012-05-15T07:11:18.580

1It would fail because each new Random() instance is being "seeded" with the same system time value as the last one (or the next one) and so each PRNG produces the same number sequence. – KeithS – 2012-05-15T17:10:30.643

Why is the toArray necessary? – Tomalak – 2011-08-03T20:22:07.087

Because the product of these Linq methods is an IEnumerable<char>, for which there isn't a built-in String constructor. It has to be converted to an explicit char[]. – KeithS – 2011-08-03T20:35:37.730

I see... Thanks! – Tomalak – 2011-08-03T20:38:15.853

1

FSharp, ~207 177

Count includes whitespace since its significant for f#

let f w=
 let r=System.Random()
 let e = Seq.length w
 (w|>Seq.mapi(fun i l->if i=0||i=e-1 then i,l else r.Next(1,e-1),l)|>Seq.sortBy fst|>Seq.map snd|>List.ofSeq).ToString()

Run with:

printfn "%s" (f "apples")

sideproject

Posted 2011-08-03T11:25:05.427

Reputation: 21

1

Java, 194 charcters

String r(String s){String[]c=s.split("");if(c.length>2)java.util.Collections.shuffle(java.util.Arrays.asList(c).subList(2,c.length-1));return(""+java.util.Arrays.asList(c)).replaceAll("\\W","");}

If you can assume java.util.* is imported, then you can shave off a fair amount of characters. Might be able to squeeze in a List variable to save a few more. If the class the r function is implemented in derives from java.util.Arrays, then even more characters can be saved.

Thomas Eding

Posted 2011-08-03T11:25:05.427

Reputation: 796

String r(String s){char[]c=s.toCharArray();if(c.length>2)java.util.Arrays.sort(c,1,c.length-1);return new String(c);} – Olivier Grégoire – 2017-07-20T13:17:49.863

&& isn't much shorter than if; try it without asList and without 'replaceAll'. [, L, l, o, a] and [Ljava.lang.String;@addbf1 might be with you. – user unknown – 2011-08-04T04:25:11.327

&& requires both sides to be boolean expressions, and shuffle has return type void. As for storing the asList into c, the types are incompatable. I could store it in a java.util.List, but that is lengthy right there. – Thomas Eding – 2011-08-04T16:18:39.547

@trinithis Yeah I just tried with && and came to the same conclusion. So I deleted my comment. – Tomalak – 2011-08-04T16:37:40.403

One can do import static java.util.Arrays.*, which is just another import instead of deriving from java.util.Arrays, which is kind of clumsy. – Rotsor – 2011-08-05T01:06:28.667

1

Scala: 112 123

def v(s:String)=if(s.size<4)s else s(0)+util.Random.shuffle(s.substring(1,s.size-1).toList).mkString+s(s.size-1)

Incorporated hints from the comments (length->size (I need this hint every time), mkString without ("")) and size-1, not -2). Thanks.

user unknown

Posted 2011-08-03T11:25:05.427

Reputation: 4 210

I think you can save 6 chars by using .size instead of .length – Gareth – 2011-08-04T08:10:47.390

You can also leave the ("") off the mkString call to save 4 more and get down to 112. There's a couple of typos too - the v(0) after the else should be s(0) and s.length-2 in the substring should be s.length-1 otherwise you lose a character in the result. – Gareth – 2011-08-04T09:20:16.797

1

Lua, 173 chars

Does what it needs to do.

function(a)return(a:gsub('(%w)(%w*)(%w)',function(a,b,c)t={}for l in b:gmatch'.'do t[#t+1]=l end while #t>0 do i=math.random(#t)a=a..table.remove(t,i)end return a..c end))end

jpjacobs

Posted 2011-08-03T11:25:05.427

Reputation: 3 440

1

Haskell, 195

import Random
import Data.List
r l=fmap(f l.g l)newStdGen
f l n=map snd$head$filter(\l->map fst l==n)$permutations$zip[0..]l
g l=take(n+2).(0:).(++[n+1]).take n.nub.randomRs(1,n)where n=length l-2

Hacked this into existence while Rotsor was making his post. This will cover all possible permutations, and I believe it does so uniformly.

The function r is the function that the user uses.

The algorithm is fairly straightforward. It generates a random list of unique numbers from 1 to n-2. Then it tacks on 0 to the front and n-1 to the end of the list. The take(n+2) is there to handle the case where the input is a single character (or an empty string for that matter). Then it searches for the corresponding permutation and returns that.

The list is generated by generating an infinite list of random numbers from 1 to n-2. Then it picks out the first occurance of each number in that range.

Thomas Eding

Posted 2011-08-03T11:25:05.427

Reputation: 796

I've been puzzled why this program always produces the same result until I've realised that one needs to call newStdGen upon each independent call to r. – Rotsor – 2011-08-04T17:52:29.737

Run it outside of ghci. Make a main function, such as main = getLine >>= r >>= putStrLn. Then compile it and execute or use runhaskell. This will solve the problem. That or exit ghci every time and restart it after every call to r. – Thomas Eding – 2011-08-04T18:17:49.350

I was testing the distribution by doing replicateM 500 $ r "12345", which returned 500 identical results, so running it outside of ghci makes no difference. – Rotsor – 2011-08-04T18:34:06.123

Actually I think you should replace getStdGen with newStdGen in your solution, so it behaves in a way most (?) would expect. – Rotsor – 2011-08-04T18:40:44.527

I see. Fixed it. Thankfully, the character count is the same :D – Thomas Eding – 2011-08-04T19:11:42.050

1

Javascript, 202 characters

function r(s){var s=s.split(""),h=[-1],n=s.length-1,t,i;h[-1]=s[0];for(i=0;++i<n;){do{t=Math.random()}while(t in h);h[t]=s[i];h[i]=t;}h.sort();for(i=0;i<n;++i)h[i]=h[h[i]];return n?h.join("")+s[n]:s[0]}

This solution has an unbiased distribution.

Algorithm:

Split input string into an array s. Consider another array h that is doubly used as a dictionary. For each letter in s at index 0 < i < s.length-1, assign a unique random number to h at i. Also map the random number in the range [0, 1) in h to the letter. The first and last letters are handled specially. Before assigning the random numbers as described above, do the analogous thing for the first letter, but hard code the number as -1 (guaranteed to be less than the smallest random number generated, which can be 0). Ignore the last letter for now. Sort h. Map h's random value to the corresponding letter. Join the array into a string and tack on the last letter. Special case for 1 character input, where we return the first character (we still crunch h because the logic is shorter that way).

Thomas Eding

Posted 2011-08-03T11:25:05.427

Reputation: 796

for(i=1;i<n;++i) --> for(i=0;++i<n;) ? – Mechanical snail – 2011-08-04T23:09:12.503

Nifty (filler.) – Thomas Eding – 2011-08-04T23:50:26.640

Why is sorting by Math.random()-.5 biased? – Tomalak – 2011-08-05T04:37:34.443

Suppose we have a 5 card deck. Then there are exactly 5! = 120 unique outcomes. If you were to "shuffle" the deck by going through the bottom to the top, swapping the current card with any card in the deck (including itself and including the layer of the deck already shuffled), this would produce 5^5 or 3125 possible outcomes. But 120 does not divide 3125 evenly. Thus by the pigeonhole principle, there exists an outcome that occurs more often than at least one other outcome. Hence the bias. – Thomas Eding – 2011-08-05T17:21:06.550

@trinithis, that is an interesting observation! However I think you did not answer the question. Sorting by Math.random() should give uniform distribution if Math.random() generates unique numbers, but in practice it does not. – Rotsor – 2011-08-06T00:48:20.053

The problem does not like in Math.random. The problem lies in how many times elements move in the sort due to the sorting algorithm itself. That is, if we had a perfect random function (with or without uniqueness), the bias would still exist. – Thomas Eding – 2011-08-08T21:37:56.927

1

Perl - 76 chars

Pure Perl implementation that requires no external modules. Also correctly handles one-letter, two-letter word edge cases.

sub r{@a=split//,pop;@a>1?join'',@a[0,(sort{rand()<=>rand}1..$#a-1),$#a]:@a}

Usage

say r('stringified') for 1 .. 20;

# Example output

srfgiietnid
sgfnieiitrd
seiifgrtnid
siigrfeintd
sgiirntiefd
siigerniftd
sifiitgnred
sftrneiiigd
sfieirtngid
sfeitirgnid
sfiertnigid
sigteifrind
sgieftirnid
sieitfrnigd
stnigirfeid
sfietrniigd
siigfrenitd
stefrniiigd
setrfiniigd
sifgtiernid

N.B. I'm not entirely convinced that the letter randomization still renders the word readable in the example above

Zaid

Posted 2011-08-03T11:25:05.427

Reputation: 1 015

1

JavaScript 132 characters:

function r(w){return w.substr(0,1)+w.substr(1,w.length-2).split('').sort(function(){return Math.random()-.5}).join('')+w.substr(-1)}

You don't need to go through point by point. If provided a function which returns something where Math.round will return a random 0,1,-1, that will be sufficient (because of how sort works).

cwallenpoole

Posted 2011-08-03T11:25:05.427

Reputation: 141

That won't keep the first and last letters in place. – Tomalak – 2012-03-18T19:14:52.797

@Tomalak Now it will. – cwallenpoole – 2012-03-20T04:16:22.717

But it does not work anymore. – Tomalak – 2012-03-20T05:08:24.493

1

TinyMUSH, 102

&_ me=left(%0,1)[ifelse(eq(strlen(%0),1),,scramble(mid(%0,1,sub(strlen(%0),2)))[right(%0,1)])]
\u(_,X)

Replace "X" with the input word. The user-defined _ attribute uses the built-in scramble() function to scramble letters between the first and last letters.

Muqo

Posted 2011-08-03T11:25:05.427

Reputation: 499

1

Clip, 24

?<lxWx],*R>%Ox{(x)x`(x)x

Here's an effective translation in pseudocode:

x = input by stdin
if len(x) < 2:
  output x
else:
  y = rotate_right(x, 1)
  y.remove_first_occurrence(first(x), last(x))
  # y is now the characters between the first and last of the input.
  shuffle(y)
  output place_at_end(last(x), place_at_beginning(first(x), y))

bcsb1001

Posted 2011-08-03T11:25:05.427

Reputation: 450

esolangs.com does not seem to exist anymore. – Tomalak – 2015-03-24T21:43:47.110

@Tomalak Fixed, had a .com instead of .org... – bcsb1001 – 2015-03-24T21:46:42.800

1

Rebol - 63

f: func[s][e: take/last s ajoin trim reduce[take s random s e]]

Ungolfed:

f: func [s] [
    e: take/last s 
    ajoin trim reduce [take s random s e]
]

Usage example:

>> f "1"
== "1"

>> f "12"
== "12"

>> f "123"
== "123"

>> f "1234"
== "1324"


NB. An alternative (but unfortunately not shorter) version would be:

f: func [s] [
    change/part next s random copy/part next s back tail s back tail s
    s
]

With golfing and minor shavings this would come out at 73 chars.

draegtun

Posted 2011-08-03T11:25:05.427

Reputation: 1 592

1

MATLAB, 48 bytes

function t=f(t)
t(2:end-1)=t(randperm(end-2)+1);

Too bad the spec says 'function', using input() would be 43 bytes. Another version, that will fail slightly on a one-length word (a becomes aa), is 34 bytes:

f=@(t)t([1 randperm(end-2)+1 end])

Sanchises

Posted 2011-08-03T11:25:05.427

Reputation: 8 530

1

Pyth - 11 bytes

Pyth is younger than this challenge so it doesn't count.

pez+hz.SPtz

Gets middle, shuffles it, then adds the rest. Takes I/O from stdout/stdin.

pez+hz      Print First letter of input, something else, and last letter of input
 .S         Shuffle
  P         All but the last
   t        All but the first
    z       The input

Maltysen

Posted 2011-08-03T11:25:05.427

Reputation: 25 023

Doesn't work for for 1-letter inputs. – Jakube – 2015-03-31T08:09:47.903

1

VBA, 128 177 151 chars

I know this is an older puzzle, but I wanted to add my two cents from

Sub o(s)
n=Left(s,1)
p=Len(s)-1
s=Right(s,p)
For i=1 To p-1
p=p-1
r=Int(p*Rnd()+1)
n=n & Mid(s,r,1)
s=Left(s,r-1) & Right(s,p-r+1)
Next
s=n & s
End Sub

Example Usage:

a = "According"
o a ' a is assigned by the passing of the reference to the 'o' sub.
a = "to"
o a ' see above...
a = "some"
o a
a = "controversial"
o a
a = "story"
o a

I was actually happily surprised to see it fare as well as it did against some of the other, more typical CG languages. After improving, this is still not the shortest, but I was happy to do it.

Gaffi

Posted 2011-08-03T11:25:05.427

Reputation: 3 411

1Does that keep the first and last letters in place and work with strings less than 3 characters long? – Tomalak – 2012-03-19T21:34:23.980

D'oh! First and last don't keep, but length is not a problem. I'll get back to you... – Gaffi – 2012-03-19T21:35:28.673

Fixed, @Tomalak. Thanks for catching that. – Gaffi – 2012-03-20T13:10:51.167

1

MATLAB, 65 47 characters

r=@(s)s([3-min(end,2):1 randperm(end-2)+1 end])

Works for strings of positive length, but fails on the empty string. Improved by using end as in jazzkingrt's solution.

This use of end can further improve jazzkingrt's solution by substituting end for length(x). However, that solution doesn't handle strings of length one correctly. (I'm not allowed to comment, so I write here instead.)

Pontus von Brömssen

Posted 2011-08-03T11:25:05.427

Reputation: 113

1

Q (42 Characters)

{(x[0]),((neg count 1_-1_x)?1_-1_x),-1#x}

Sample Usage:

q){(x[0]),((neg count 1_-1_x)?1_-1_x),-1#x} "elephant"
"eeahlnpt"
q){(x[0]),((neg count 1_-1_x)?1_-1_x),-1#x} "ant"
"ant"

sinedcm

Posted 2011-08-03T11:25:05.427

Reputation: 410

Doesn't work for single letter words, need to work on that. – sinedcm – 2012-03-21T17:52:23.403

41 bytes with {$[3<c:(#)x;(x 0),((2-c)?-1_1_x),-1#x;x]}, works with 0, 1, 2 etc length strings too. – streetster – 2017-06-13T15:46:24.943

1

Mathematica 98 chars

Not the most economical code but fun to write.

s holds the input sentence (as a string).

Row[StringJoin @@@ (Characters@# /. {f_, m___, e_} :>  
   Flatten@{f, RandomSample@{m}, e} & /@ StringSplit@s), " "]

For example, when `s = "This sentence is fairly easy to read.",

output

DavidC

Posted 2011-08-03T11:25:05.427

Reputation: 24 524

0

Python 3, 75 73 bytes

Thanks to @WW for saving me 2 bytes

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

Try it online!

JathOsh

Posted 2011-08-03T11:25:05.427

Reputation: 31

1You can remove the s= to save 2 bytes. – Post Rock Garf Hunter – 2018-07-18T03:09:47.890

@WW I see that you could do that if the import wasn't there but how would you call it in in the "Try it online!" – JathOsh – 2018-07-18T03:21:16.703

1Try it online! – Post Rock Garf Hunter – 2018-07-18T03:22:01.633

@WW I see now Thank You! – JathOsh – 2018-07-18T03:22:42.100

0

JavaScript, 93 bytes

(_,[a,[...b],c,d=b.sort(_=>Math.random()-.5).join``]=_.match(/(^.)|[^\1]+(?=.$)|.$/g))=>a+d+c

Try it online!

Using .match() with regular expression /(^.)|[^\1]+(?=.$)|.$/g to match first character, one or more characters that at not the first character followed by one character and end of string, and character followed by end of string and .sort() approach used at the question.

guest271314

Posted 2011-08-03T11:25:05.427

Reputation: 1

0

Javascript 98 bytes

a=>{c=l=a.length-1;for(b=[a[0]];--c;)d=Math.random()*99|0,b[d]?c++:b[d]=a[c];return b.join``+a[l]}

Try it online!

This assigns each letter other than the first and last to a random array index, and then joins the array into a string. 99 can be changed to 9e9 to work on (much!) longer words at the cost of a byte, but then join takes almost a minute. Besides, there aren't many words that even approach 100 characters.

Because of that, this is 12 bytes shorter (86 bytes) and works almost every time:

a=>{c=l=a.length-1;for(b=[a[0]];--c;)b[Math.random()*9e9|0]=a[c];return b.join``+a[l]}

Spitemaster

Posted 2011-08-03T11:25:05.427

Reputation: 695

0

05AB1E, 12 11 bytes

g≠ićs¨.rIθJ

Try it online or verify some more inputs.

Fun 12 11 bytes alternative:

g͸1.ø£€.rJ

Try it online or verify some more inputs.

Both version also work for strings with less than 3 characters. The first one could be just ćs¨.rIθJ (8 bytes), but then it doesn't work for single-character strings ("a" becomes "aa").

Explanation:

g              # Take the length of the (implicit) input
               #  i.e. "howaboutthis" → 12
               #  i.e. "a" → 1
 ≠i            # If this length is not 1:
               #   i.e. 12 → 1 (truthy)
               #   i.e. 1 → 0 (falsey)
   ć           #  Extract the head of the (implicit) input
               #   i.e. "howaboutthis" → "owaboutthis" and "h"
    s          #  Swap so the list (minus head) is at the top of the stack again
     ¨         #  Remove the last character
               #   i.e. "owaboutthis" → "owaboutthi"
      .r       #  Randomly shuffle the characters
               #   i.e. "owaboutthi" → "oohbtwtiua"
        Iθ     #  Take the last character of the input
               #   i.e. "howaboutthis" → "s"
          J    #  Join the values on the stack together (and output implicitly)
               #   i.e. "h", "oohbtwtiua", "s" → "hoohbtwtiuas"
               # (Implicit else)
               #  (Output the input as is implicitly)
               #   i.e. "a"

g              # Take the length of the (implicit) input
               #  i.e. "howaboutthis" → 12
               #  i.e. "a" → 1
 Í             # Subtract 2
               #  i.e. 12 → 10
               #  i.e. 1 → -1
  ¸            # Wrap it into a list
               #  i.e. 10 → [10]
               #  i.e. -1 → [-1]
   1.ø         # Surround it with 1s
               #  i.e. [10] → [1,10,1]
               #  i.e. [-1] → [1,-1,1]
      £        # Split the (implicit) input into parts of that size
               #  i.e. "howaboutthis" and [1,10,1] → ["h","owaboutthi","s"]
               #  i.e. "a" and [1,-1,1] → ["a","",""]
       €       # Map each value to:
        .r     #  Randomly shuffle the characters
               #   i.e. ["h","owaboutthi","s"] → ["h","oohbtwtiua","s"]
               #   i.e. ["a","",""] → ["a","",""]
          J    # Join the values in the list together (and output implicitly)
               #  i.e. ["h","oohbtwtiua","s"] → "hoohbtwtiuas"
               #  i.e. ["a","",""] → "a"

Kevin Cruijssen

Posted 2011-08-03T11:25:05.427

Reputation: 67 575

0

Python - 103 96 90 88 85 109 characters

import random as r
def s(x):
 if len(x)>3:y=list(x[1:-1]);r.shuffle(y);return x[0]+''.join(y)+x[-1]
 return x

props to @dr jimbob for the "import as" bit and for catching my non-conformance with the spec. props also to @user unknown for getting the spec clarified.

Edit: updated to conform to short-words spec.

arrdem

Posted 2011-08-03T11:25:05.427

Reputation: 805

Sorry about the other comment; my mistake; though I still think you need a return x[0]+''.join(y)+x[-1] at the end; also could change y=[x[a] for a in range(1,len(x))] to y=[x[1:-1]] – dr jimbob – 2011-08-03T17:18:21.450

The [1:-1] actually doesn't work, and results in ['hateve'] for input of 'whatever'. My bad on the last letter, good catch. – arrdem – 2011-08-03T19:28:36.180

I meant y=list(x[1:-1]). But you are supposed to not shuffle the first and last letter, so you need to change your return to return x[0]+''.join(y)+x[-1] – dr jimbob – 2011-08-03T19:55:36.383

nice list(). I had [b for b in x[1:-1]] for a while there instead. – arrdem – 2011-08-03T20:05:58.223

Doesn't work for input like 'I'; return 'II'. – user unknown – 2011-08-04T03:24:56.930

@user - you are right, but is there any solution here which does not demonstrate that error in the interest of conciseness? Not that I can see. Implied in the spec is that all inputs will be of len(x) > 2. Otherwise how do you scramble the letters in the middle? Unless that test case gets added to the spec, I will continue to ignore it as undefined behavior. – arrdem – 2011-08-04T03:51:16.473

@rmckenzie I have to admit that did not think of that; my bad. Of course short words should work, I've added a length check to my question. – Tomalak – 2011-08-04T07:10:30.577

@mckenzie: Before I checked most of the solutions I have an installed interpreter or compiler at hand, there already where some solutions which handled 'I' correctly: 1x Java, 1x Scala, 1xC++, 1xRuby at least. I didn't test php, mono, ruby1.9 and much more. – user unknown – 2011-08-04T10:01:48.570

@user Many people have updated their answers. If you down-voted them for this reason alone, I'd think it would be fair if your'd revise your downvotes. – Tomalak – 2011-08-04T17:14:09.610

I already revised every downvote I made, where the code now handles the problem. I would find it unfair, if a solution is only as short as it is, because it doesn't handle the case. But you're right; again there are new corrections. – user unknown – 2011-08-04T17:27:03.780

Updated to reflect the change in spec. – arrdem – 2011-08-04T19:09:17.717