How do I shuffle the characters in a string in JavaScript?

JavascriptString

Javascript Problem Overview


In particular, I want to make sure to avoid the mistake made in Microsoft's Browser Choice shuffle code. That is, I want to make sure that each letter has an equal probability of ending up in each possible position.

e.g. Given "ABCDEFG", return something like "GEFBDCA".

Javascript Solutions


Solution 1 - Javascript

I modified an example from the Fisher-Yates Shuffle entry on Wikipedia to shuffle strings:

String.prototype.shuffle = function () {
    var a = this.split(""),
        n = a.length;

    for(var i = n - 1; i > 0; i--) {
        var j = Math.floor(Math.random() * (i + 1));
        var tmp = a[i];
        a[i] = a[j];
        a[j] = tmp;
    }
    return a.join("");
}
console.log("the quick brown fox jumps over the lazy dog".shuffle());
//-> "veolrm  hth  ke opynug tusbxq ocrad ofeizwj"

console.log("the quick brown fox jumps over the lazy dog".shuffle());
//-> "o dt hutpe u iqrxj  yaenbwoolhsvmkcger ozf "

More information can be found in Jon Skeet's answer to Is it correct to use JavaScript Array.sort() method for shuffling?.

Solution 2 - Javascript

If "truly" randomness is important, I recommend against this. See my below edit.

I just wanted to add my favorite method for a little variety ;)

Given a string:

var str = "My bologna has a first name, it's O S C A R.";

Shuffle in one line:

var shuffled = str.split('').sort(function(){return 0.5-Math.random()}).join('');

Outputs:

oa, a si'rSRn f gbomi. aylt AtCnhO ass eM
as'oh ngS li Ays.rC nRamsb Oo ait a ,eMtf
y alCOSf e gAointsorasmn bR Ms .' ta ih,a

EDIT: As @PleaseStand has pointed out, this doesn't meet OP's question at all since it does suffer from "Microsoft's Browser Choice shuffle" code. This isn't a very good randomizer if your string needs to be close to random. It is however, awesome at quickly "jumbling" your strings, where "true" randomness is irrelevant.

The article he links below is a great read, but explains a completely different use case, which affects statistical data. I personally can't imagine a practical issue with using this "random" function on a string but as a coder, you're responsible for knowing when not to use this.

I've left this here for all the casual randomizers out there.

Solution 3 - Javascript

Shortest One Liner:

const shuffle = str => [...str].sort(()=>Math.random()-.5).join('');

Does not guarantee statistically equal distribution but usable in most cases for me.

const shuffle = str => [...str].sort(()=>Math.random()-.5).join('');
document.write(shuffle("The quick brown fox jumps over the lazy dog"));

Solution 4 - Javascript

Even though this has been answered, I wanted to share the solution I came up with:

function shuffleWord (word){
    var shuffledWord = '';
    word = word.split('');
    while (word.length > 0) {
      shuffledWord +=  word.splice(word.length * Math.random() << 0, 1);
    }
    return shuffledWord;
}

// 'Batman' => 'aBmnta'

You can also try it out (jsfiddle).

Snippet is 100k shuffles of 3 character string:

var arr={}, cnt=0, loops=100000, ret;
do{
  ret=shuffle('abc');
  arr[ret]=(ret in arr?arr[ret]+1:1);
}while(++cnt<loops);  

for(ret in arr){
  document.body.innerHTML+=ret+' '+arr[ret]+' '+(100*arr[ret]/loops).toFixed(1)+'%<br>';
}

function shuffle(wd){var t="";for(wd=wd.split("");wd.length>0;)t+=wd.splice(wd.length*Math.random()<<0,1);return t}

Solution 5 - Javascript

Using Fisher-Yates shuffle algorithm and ES6:

// Original string
let string = 'ABCDEFG';

// Create a copy of the original string to be randomized ['A', 'B', ... , 'G']
let shuffle = [...string];

// Defining function returning random value from i to N
const getRandomValue = (i, N) => Math.floor(Math.random() * (N - i) + i);

// Shuffle a pair of two elements at random position j (Fisher-Yates)
shuffle.forEach( (elem, i, arr, j = getRandomValue(i, arr.length)) => [arr[i], arr[j]] = [arr[j], arr[i]] );

// Transforming array to string
shuffle = shuffle.join('');

console.log(shuffle);
// 'GBEADFC'

Solution 6 - Javascript

You can't shuffe a string in place but you can use this:

String.prototype.shuffle = function() {
    var len = this.length;
    var d = len;
    var s = this.split("");
    var array = [];
    var k, i;
    for (i = 0; i < d; i++) {
        k = Math.floor(Math.random() * len);
        array.push(s[k]);
        s.splice(k, 1);
        len = s.length;
    }
    for (i = 0; i < d; i++) {
        this[i] = array[i];
    }
    return array.join("");
}

var s = "ABCDE";
s = s.shuffle();
console.log(s);

Solution 7 - Javascript

Single line solution and limited output length...

var rnd = "ABCDEF23456789".split('').sort(function(){return 0.5-Math.random()}).join('').substring(0,6);

Solution 8 - Javascript

String.prototype.shuffle=function(){
   
   var that=this.split("");
   var len = that.length,t,i
   while(len){
    i=Math.random()*len-- |0;
    t=that[len],that[len]=that[i],that[i]=t;
   }
   return that.join("");
}

Solution 9 - Javascript

                  shuffleString = function(strInput){
                     var inpArr = strInput.split("");//this will give array of input string
                     var arrRand = []; //this will give shuffled array
                     var arrTempInd = []; // to store shuffled indexes
                     var max = inpArr.length;
                     var min = 0;
                     var tempInd;
                     var i =0 ;
                        
                      do{
                           tempInd = Math.floor(Math.random() * (max - min));//to generate random index between range
                           if(arrTempInd.indexOf(tempInd)<0){ //to check if index is already available in array to avoid repeatation
                                arrRand[i] = inpArr[tempInd]; // to push character at random index
                                arrTempInd.push(tempInd); //to push random indexes 
                                i++;
                            }
                       }
                        while(arrTempInd.length < max){ // to check if random array lenght is equal to input string lenght
                            return arrRand.join("").toString(); // this will return shuffled string
                        }
                 };

Just pass the string to function and in return get the shuffled string

Solution 10 - Javascript

A different take on scrambling a word. All other answers with enough iterations will return the word unscrambled, mine does not.

var scramble = word => {

	var unique = {};
	var newWord = "";
	var wordLength = word.length;

	word = word.toLowerCase(); //Because why would we want to make it easy for them?

	while(wordLength != newWord.length) {

		var random = ~~(Math.random() * wordLength);

		if(

		  unique[random]
		  ||
		  random == newWord.length && random != (wordLength - 1) //Don't put the character at the same index it was, nore get stuck in a infinite loop.

		) continue; //This is like return but for while loops to start over.

		unique[random] = true;
		newWord += word[random];

	};

	return newWord;

};

scramble("God"); //dgo, gdo, ogd

Solution 11 - Javascript

Yet another Fisher-Yates implementation:

const str = 'ABCDEFG',

      shuffle = str => 
        [...str]
          .reduceRight((res,_,__,arr) => (
            res.push(...arr.splice(0|Math.random()*arr.length,1)),
            res) ,[])
          .join('')

console.log(shuffle(str))

.as-console-wrapper{min-height:100%;}

Solution 12 - Javascript

Just for the sake of completeness even though this may not be exactly what the OP was after as that particular question has already been answered.

Here's one that shuffles words.

Here's the regex explanation for that: https://regex101.com/r/aFcEtk/1

And it also has some funny outcomes.

// Shuffles words // var str = "1 2 3 4 5 6 7 8 9 10"; var str = "the quick brown fox jumps over the lazy dog A.S.A.P. That's right, this happened."; var every_word_im_shuffling = str.split(/\s\b(?!\s)/).sort(function(){return 0.5-Math.random()}).join(' '); console.log(every_word_im_shuffling);

Solution 13 - Javascript

Rando.js uses a cryptographically secure version of the Fisher-Yates shuffle and is pretty short and readable.

console.log(randoSequence("This string will be shuffled.").join(""));

<script src="https://randojs.com/2.0.0.js"></script>

Solution 14 - Javascript

String.prototype.shuffle = function(){
  return this.split('').sort(function(a,b){
    return (7 - (Math.random()+'')[5]);
  }).join('');
};

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLiamView Question on Stackoverflow
Solution 1 - JavascriptAndy EView Answer on Stackoverflow
Solution 2 - JavascriptJoel MellonView Answer on Stackoverflow
Solution 3 - JavascriptchickensView Answer on Stackoverflow
Solution 4 - JavascriptMaximilian LindseyView Answer on Stackoverflow
Solution 5 - JavascriptErik Martín JordánView Answer on Stackoverflow
Solution 6 - JavascriptGiacomo CasadeiView Answer on Stackoverflow
Solution 7 - JavascriptMCunha98View Answer on Stackoverflow
Solution 8 - Javascriptuser1289673View Answer on Stackoverflow
Solution 9 - JavascriptMayur NandaneView Answer on Stackoverflow
Solution 10 - JavascriptDarkrumView Answer on Stackoverflow
Solution 11 - JavascriptYevgen GorbunkovView Answer on Stackoverflow
Solution 12 - JavascriptSteView Answer on Stackoverflow
Solution 13 - JavascriptAaron PlocharczykView Answer on Stackoverflow
Solution 14 - JavascriptCaptain FailView Answer on Stackoverflow