55
\$\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\$
  • 3
    \$\begingroup\$ Haskell, 4 characters: r=id. \$\endgroup\$ – Thomas Eding Aug 3 '11 at 20:01
  • 2
    \$\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\$ – Thomas Eding Aug 3 '11 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 '11 at 7:37
  • 3
    \$\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\$ – Thomas Eding Aug 4 '11 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\$ – Nate Koppenhaver Aug 4 '11 at 18:33

74 Answers 74

1
\$\begingroup\$

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.

\$\endgroup\$
1
\$\begingroup\$

><>, 40 bytes

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

Try it here!

\$\endgroup\$
1
\$\begingroup\$

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.

\$\endgroup\$
  • 1
    \$\begingroup\$ Does that keep the first and last letters in place and work with strings less than 3 characters long? \$\endgroup\$ – Tomalak Mar 19 '12 at 21:34
  • \$\begingroup\$ D'oh! First and last don't keep, but length is not a problem. I'll get back to you... \$\endgroup\$ – Gaffi Mar 19 '12 at 21:35
  • \$\begingroup\$ Fixed, @Tomalak. Thanks for catching that. \$\endgroup\$ – Gaffi Mar 20 '12 at 13:10
1
\$\begingroup\$

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());
}
\$\endgroup\$
  • \$\begingroup\$ Why is the toArray necessary? \$\endgroup\$ – Tomalak Aug 3 '11 at 20:22
  • \$\begingroup\$ 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[]. \$\endgroup\$ – KeithS Aug 3 '11 at 20:35
  • \$\begingroup\$ I see... Thanks! \$\endgroup\$ – Tomalak Aug 3 '11 at 20:38
  • \$\begingroup\$ there's no Rand class in C# - it's Random. Also, name the function S instead of Shuf to gain some chars. \$\endgroup\$ – Cristian Lupascu May 15 '12 at 7:06
  • 1
    \$\begingroup\$ It 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. \$\endgroup\$ – KeithS May 15 '12 at 17:10
1
\$\begingroup\$

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;
\$\endgroup\$
1
\$\begingroup\$

><>, 19 bytes

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

Try it online!

Works for words of less than 3 length.

\$\endgroup\$
1
\$\begingroup\$

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!

\$\endgroup\$
  • \$\begingroup\$ 89 bytes changing the sampling a bit \$\endgroup\$ – Giuseppe Jul 17 '18 at 20:40
  • \$\begingroup\$ Oops, 83 bytes \$\endgroup\$ – Giuseppe Jul 17 '18 at 20:41
  • \$\begingroup\$ Aaaand another one for good measure: 79 bytes -- in all fairness to me, I haven't gotten much sleep the last few days. \$\endgroup\$ – Giuseppe Jul 17 '18 at 20:48
  • \$\begingroup\$ @Giuseppe This is much better indeed! \$\endgroup\$ – JayCe Jul 18 '18 at 0:23
1
\$\begingroup\$

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.

\$\endgroup\$
1
\$\begingroup\$

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
\$\endgroup\$
0
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ 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]] \$\endgroup\$ – dr jimbob Aug 3 '11 at 17:18
  • \$\begingroup\$ The [1:-1] actually doesn't work, and results in ['hateve'] for input of 'whatever'. My bad on the last letter, good catch. \$\endgroup\$ – arrdem Aug 3 '11 at 19:28
  • \$\begingroup\$ 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] \$\endgroup\$ – dr jimbob Aug 3 '11 at 19:55
  • \$\begingroup\$ nice list(). I had [b for b in x[1:-1]] for a while there instead. \$\endgroup\$ – arrdem Aug 3 '11 at 20:05
  • \$\begingroup\$ Doesn't work for input like 'I'; return 'II'. \$\endgroup\$ – user unknown Aug 4 '11 at 3:24
0
\$\begingroup\$

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!

\$\endgroup\$
  • 1
    \$\begingroup\$ You can remove the s= to save 2 bytes. \$\endgroup\$ – Wheat Wizard Jul 18 '18 at 3:09
  • \$\begingroup\$ @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!" \$\endgroup\$ – JathOsh Jul 18 '18 at 3:21
  • 1
    \$\begingroup\$ Try it online! \$\endgroup\$ – Wheat Wizard Jul 18 '18 at 3:22
  • \$\begingroup\$ @WW I see now Thank You! \$\endgroup\$ – JathOsh Jul 18 '18 at 3:22
0
\$\begingroup\$

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.

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

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]}
\$\endgroup\$
0
\$\begingroup\$

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"
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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