Skip to content Skip to sidebar Skip to footer

Weighted Random Number Generation In Javascript

I have an array that looks something like this: [ { plays: 0, otherData: someValues }, { plays: 4, otherData: someValues }, { pl

Solution 1:

I would do what you want to do with loops. Total up the max number of plays for any song in the list, then reverse the probability by calculating a number that is reverse weighted and choosing from the reverse total. Something like this:

functionpickRandom(myArray) {
    var maxPlays = 0, reverseTotPlays = 0, ipl, picked, revAcc = 0;

    // Empty array or bad input paramif (!myArray || !myArray.length) {
        return -1;
    }

    // Calculate the max plays for any song in the listfor (ipl = 0;  ipl < myArray.length;  ++ipl) {
        if (myArray[ipl].plays > maxPlays) {
            maxPlays = myArray[ipl].plays;
        }
    }
    maxPlays += 1;   // Avoid excluding max songs// Calculate the reverse weighted total playsfor (ipl = 0;  ipl < myArray.length;  ++ipl) {
        reverseTotPlays += maxPlays - myArray[ipl].plays;
    }

    // Choose a random number over the reverse weighted spectrum
    picked = ~~(Math.random() * reverseTotPlays);

    // Find which array member the random number belongs tofor (ipl = 0;  ipl < myArray.length;  ++ipl) {
        revAcc += maxPlays - myArray[ipl].plays;
        if (revAcc > picked) {
            return ipl;
        }
    }
    return myArray.length - 1;
}

var pp = [{ plays: 3 }, { plays: 1 }, { plays: 2 }];
console.log(pickRandom(pp));

Working JSFiddle Here

Edit: If you don't want a zero probability on playing the songs that have been played the max times in the list, add +1 to maxPlays after the first loop.

Solution 2:

It's probably easiest to do a two-step selection, start by selecting a random song, then see if that song passes a second test designed to preferentially select less-played songs. If it fails that second test, discard it and start the whole process again.

An example (forgive me if I've made a mistake, it's been a long time since I did any javascript):

functionpickRandom(){
    var candidate;
    while (true){
        candidate = songs[Math.round(Math.random() * (songs.length - 1))];
        //largest_played is the largest number of plays of any one song// I've magiced it out of nowhere here, find it in a manner that// suits your program.if ( candidate.plays/largest_played < math.random() ){
            return candidate;
        }
    }
} 

Obviously, there's a lot of gloss and error checking missing, but it should be enough to get you started.

Post a Comment for "Weighted Random Number Generation In Javascript"