Tuesday, December 16, 2008

Randomize an array

First of all the why:

you want to serve back several text ads in a random order through one adserver call. You would do this to save on calls - for instance a block of 8 text ads which are changed on a weekly basis could instead be changed in to one block that gets updated, randomized with javascript, and printed on the screen. This saves 7 extra calls a pop - which means that you save on adserving fees.

The current methods:

There are two methods suggested. The first is faulty, and if you're using it - stop now:

1)

Array.sort(function(){return (Math.round(Math.random())-0.5);});

now the idea behind this is that you use the sort method for an array, but randomly decide which of the two elements is higher. This does not work because the implementation of the sort method can be different between javascript engine implementations. In fact, give it a go. Make a new array of 10 digits and print out the results a hundred times. The answers are definitely not random.

2)

The second method is the Fisher-Yates which has been used to shuffle cards completely randomly in the past. Although a good algorithm, it requires a second array and too many swapping routines:

function fisherYates ( myArray ) {
  var i = myArray.length;
  if ( i == 0 ) return false;
  while ( --i ) {
     var j = Math.floor( Math.random() * ( i + 1 ) );
     var tempi = myArray[i];
     var tempj = myArray[j];
     myArray[i] = tempj;
     myArray[j] = tempi;
   }
}

So how should it be done?

THE ANSWER:

for(i=0;i<array.length;i++)
array.splice(Math.round(Math.random()*i),0,array.pop());

using the power of javascript array functions we can make this work with most of the calculations being done by the libraries - which are always nicely optimised. 

So how does it work?

we only use the one array, but we divide it in to two separate logical parts. The randomized array, and the elements yet to be put in to the array.

What we do is grab the last element of the right side of the array (elements to be randomized) then place it randomly in the left side of the array (elements already randomized). This is much quicker with smaller data-sets than fisher-yates, but I will give no guarantees for data sets over 100.

enjoy!

No comments: