How do I shuffle the characters in a string in JavaScript?
JavascriptStringJavascript 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('');
};