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

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".

Answers:

Answer

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?.

Answer

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.

Answer

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

function shuffelWord (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).

Answer

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
Answer

If you're after neat and beautiful one-liners as I am, you might like my ES6 implementation:

const str = 'ABCDEFG';

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

console.log(shuffle(str));

Answer

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

Answer
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("");
}
Answer
                  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

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

Shortest One Liner:

let shuffled = str.split('').sort(()=>(Math.random()-0.5)).join('');
Answer

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

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>

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.