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

Solution 1:

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:

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:

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:

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

Solution 5:

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'