...

View Full Version : How to stop randomizing Array repeats



meridian
06-29-2012, 03:02 PM
Hi

Just wondering when randomizing values in an array how I can prevent the same value being randomly generated twice in a row (ie value stays the same). In my vocab flashcards script when clicking 'next word' it sometimes just returns the same word. Note: I'm not looking to randomize the array and then step through it incrementally. It's ok if the word pops up again soon in the stack.



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Japanese Flashcards</title>
</head>

<body>

<h1>Japanese Flashcards</h1>
<p id="japanese"></p>
<p id="english">&nbsp;</p>

<button onclick="showEnglish()">Answer</button>
<button onclick="nextWord()">Next word</button>

<script type="text/javascript">
var words =
[
["taberu", "to eat"],
["yomu", "to read"],
["iku", "to go"],
["kaku", "to write"],
["yomu", "to drink"],

];
var cnt = Math.floor((Math.random()*5)+0);
document.getElementById("japanese").innerHTML=words[cnt][0];

function showEnglish()
{
document.getElementById("english").innerHTML = words[cnt][1];
}

function nextWord()
{
cnt = Math.floor((Math.random()*5)+0);


document.getElementById("japanese").innerHTML = words[cnt][0]
document.getElementById("english").innerHTML='&nbsp;';
}


</script>
</body>
</html>

vwphillips
06-29-2012, 03:29 PM
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Japanese Flashcards</title>
</head>

<body>

<h1>Japanese Flashcards</h1>
<p id="japanese"></p>
<p id="english">&nbsp;</p>

<button onclick="showEnglish()">Answer</button>
<button onclick="nextWord()">Next word</button>

<script type="text/javascript">
var words =
[
["taberu", "to eat"],
["yomu", "to read"],
["iku", "to go"],
["kaku", "to write"],
["yomu1", "to drink"],

];
var cnt = Math.floor((Math.random()*5)+0);
document.getElementById("japanese").innerHTML=words[cnt][0];

function showEnglish()
{
document.getElementById("english").innerHTML = words[cnt][1];
}

function nextWord()
{
var ncnt = Math.floor((Math.random()*5)+0);
while (ncnt==cnt){
ncnt = Math.floor((Math.random()*5)+0);
}
cnt=ncnt;
document.getElementById("japanese").innerHTML = words[cnt][0]
document.getElementById("english").innerHTML='&nbsp;';
}


</script>
</body>
</html>

meridian
06-30-2012, 01:27 AM
Thanks vwphillips. That makes sense but interestingly when I tested it it still occasionally returns the same word (the word stays the same). I'm not sure why. Also, it doesn't seem to be particularly random, but perhaps it is just because it is a small data set.

007julien
06-30-2012, 02:11 AM
An other method could consist to sort randomly the array (with a myArray.sort(function(a,b){return 0.5-Math.random();})) to take the n first elements...

But with many elements, all this methods can become very long ! A variant consists to choose progressively the elements among the remaining elements. Here is an example...


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="fr">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta http-equiv="cache-control" content="no-cache">
<meta name="generator" content="PSPad editor, www.pspad.com">
<title>Random Values</title>
<style type="text/css">
body {margin:0;padding:0;font-family:Georgia;text-align:center;}
#pge {display:block;width:500px;margin:3px auto;}
p.snd {cursor:pointer;color:#909;}
</style>
</head>
<body>
<div id="pge">
<p>A simple method to choosec 50 item among 500<br>
(without sorting the whole collection)</p>
<p id="rsp"></p>
<p>Click on the page for a new generation</p>
</div>
<script type="text/javascript">
function choose(){
// With for example 500 items (from 01 to 500)
var nbrItm=500,nbrTrt=0,nbrAtr=50;// Total number of item, number of pulled items and number to be pulled
var itmLst='',itmObj={} // array and object with pulled items
do {var k=1+Math.floor(Math.random()*(nbrItm-nbrTrt));// choose of a rank among the remaining items
// Reduce k for every remainig item to take the kth, when k is null
for (var i=1;;i++) if (typeof(itmObj[i])!='number' && (--k)==0){
itmObj[i]=1;itmLst+=','+i;break;}
nbrTrt++}
while (nbrTrt!=nbrAtr);
itmLst=itmLst.substr(1).split(/,/g).sort(function(a,b){return a-b;}).join(', ');
document.getElementById('rsp').innerHTML=itmLst;
}
choose();
window.onclick=choose;
</script>
</body>
</html>This code sort the choosing items

felgall
06-30-2012, 03:42 AM
An other method could consist to sort randomly the array (with a myArray.sort(function(a,b){return 0.5-Math.random();})) to take the n first elements...

Using 0.75 instead of 0.5 in that calculation will produce results closer to being random. Anything less than 0.75 is biased toward the original order.

meridian
06-30-2012, 04:37 AM
007julien - I think that is an interesting solution. I will need to study your code though to get my head around it more.

felgall - That would solve my apparent lack of randomness. I guess the myArray.sort function is more suited to a randomized incremental array though.

Thanks for that guys.

Philip M
06-30-2012, 09:14 AM
If all you want to do is prevent the same word appearing twice in succession then you could use:-


var cnt = 0;
var previous = 0;
while(cnt == previous) {
cnt = Math.floor(Math.random()*5);
}
previous = cnt;
alert (cnt); // for testing

In other words, if the generated random number is the same as the previous one, generate another one.
Not strictly random then, but good enough for the purpose. Obviously the larger the number of words the less likely a repeat anyway.

You could extend this so that the same word was not repeated in any series of three:-


var cnt = 0;
var previous = 0;
var beforethat = 0;

while ((cnt == previous) || (cnt == beforethat)) {
cnt = Math.floor(Math.random()*5);
}
beforethat = previous;
previous = cnt;
alert (cnt); // for testing

meridian
06-30-2012, 11:26 AM
Philip M - that works perfectly. Just what I was trying to do.

Thanks heaps

007julien
06-30-2012, 05:59 PM
Take care. The proposed method to sort an array with a function which compare randomly two values is not right (with 0.5 and even more with 0.75) ! The values are generally not uniformly distributed in the interval [0,1) !


// The results of this method depends on the browser
mydArray.sort(function(a,b){return Math.random()-0.5)})


The following script shows the distribution obtained with the three methods (the values are grouped by 4 to smooth the distributions)

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="fr">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta http-equiv="cache-control" content="no-cache">
<meta name="generator" content="PSPad editor, www.pspad.com">
<title>Random Values</title>
<style type="text/css">
body {margin:0;padding:0;font-family:Georgia;text-align:center;}
#pge {display:block;width:900px;margin:3px auto;text-align:left;font-size:9px;}
p{font-size:12px;font-weight:bold;}
.grp {font-family:"courier new";color:#fff;font-weight:500;}
.ble {padding:0px;background-color:#039;font-size:6px;}
</style>
</head>
<body>
<div id="pge">

</div>
<script type="text/javascript">
var cards=[];for (var i=0;i<52;i++) cards[i]=i;
function affiche(o){var i,j,k,g='',s=0,t;
for (i=0;i<13;i++){j=o[i];s+=j;
g+=(i<10?'&nbsp;':'')+i+' <span class="ble" style="padding-left:'+((k=Math.ceil(j/3))<800?k:800)+'px" height="5px">'+j+'</span><br>';
}
document.getElementById('pge').innerHTML+='<p><span class="grp">'+g+'</span><br>Somme :'+s+'</p>';
}

var randomCard=[];for (var i=0;i<13;i++) randomCard[i]=0;
for (var i=0;i<5000;i++) {
var newCards=cards.slice(0);
newCards.sort(function(a,b){return Math.random()-0.5});
randomCard[Math.floor(newCards[0]/4)]+=1;
}
document.getElementById('pge').innerHTML+='<p>Random sort with 0.5 </p>';
affiche(randomCard);

var randomCard=[];for (var i=0;i<13;i++) randomCard[i]=0;
for (var i=0;i<5000;i++) {
var newCards=cards.slice(0);
newCards.sort(function(a,b){return Math.random()-0.75});
randomCard[Math.floor(newCards[0]/4)]+=1;
}
document.getElementById('pge').innerHTML+='<p>Random sort with 0.75 </p>';
affiche(randomCard);
var randomCard=[];for (var i=0;i<13;i++) randomCard[i]=0;
for (var i=0;i<5000;i++) randomCard[Math.floor(Math.floor(Math.random()*52)/4)]+=1;
document.getElementById('pge').innerHTML+='<p>With random number </p>';
affiche(randomCard);
</script>
</body>
</html>Run this page on IE, Mozilla FireFox, Safari, Opera, to compare the results. Only Google Chrome semms to give uniformly distributed values with the three methods !

Philip M
06-30-2012, 06:16 PM
For an unbiased array shuffle routine see

http://www.codingforums.com/showthread.php?p=1239568 (author Lerura)

meridian
07-01-2012, 05:48 AM
Wow. It's amazing the difference between the different methods used. An effective demonstration. Thanks.



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum