Weighting Random Selections

Authored September 2001

This code illustrates an example of how to deal with weighted random selections. In other words it helps build a list where certain results, although still random, are more likely than others.

Explanation

Let's take an example: for a public opinion poll you have created code that asks each visitor to your site one of six random questions. If each question had a one in six chance of being displayed then the "RandRange()" function would do the job. But, for the sake of argument let's say that these questions vary in importance and that the first question should appear very rarely, the second a bit more often, and so on with the fifth and sixth question questions appearing almost all the time.

We can represent this as a list of numeric weightings, one per possible result, with higher numbers being more commonly returned. The weightings over the total of all the weightings represent the probability of each possible outcome. In our case let's say this is the list of weightings for our six questions: "1,3,5,11,30,50"; the total of the weightings is 100. We can describe each weighting as a probability such that if we were to generate a random number between one and one hundred that number would fall in a range that would match an option. The following table illustrates this:

WeightingRandom NumberResult
11Question 1
32-4Question 2
55-9Question 3
1110-20Question 4
3021-50Question 5
5051-100Question 6

In code this system mimics this by generating the random number based on the total of the weightings and then looping over the list of weightings to find which range the random number falls in.

The Code

The first section of code creates two lists: one of the possible results and a second, corresponding list of the weightings for each possibility. The next few lines count the number of possibilities and total the weightings. Line 9 generates a random number. Line 11 sets the "ElectedOption" variable which will contain the position of the result corresponding to the random number

Lines 13 to 20 actually search for the result by looping over the list of weightings. The loop first increments "ElectedOption". The <CFIF> checks to see if the current option is greater than or equal to the random number. If so the loop is broken an "ElectedOption" contains the position of the result and the "ListGetAt()" function can be used to get the result. If not the current weighting is subtracted from the random number and the loop repeats.

Weighting Random Selections: Code Listing 1

Open this Code in a larger Window:
With Line Numbers or Without Line Numbers

Let's say, using the same example as above, that the random number returned was 13 the loop would, simply speaking, do this:

  1. Is 1 (the first weighting) greater than or equal 13? No, so we minus 1 from 13 and get 12.
  2. Is 3 (the second weighting) greater than or equal 12? No, so we minus 3 from 12 and get 9.
  3. Is 5 (the third weighting) greater than or equal 9? No, so we minus 5 from 9 and get 4.
  4. Is 11 (the fourth weighting) greater than or equal 4? Yes, so the fourth possibility is our result and we end the loop.

Honestly the math isn't really important. Just modifying the possibility and weighting lists from the above code with your own data.

An Example

The following table is generated by running the Weighting Random Selections code 100 times. The weightings and the occurances should be roughly close. You can refresh this page to see another set of results.

List ItemWeightingOccurances (out of 100)
One14
Two35
Three54
Four1112
Five3030
Six5045

Uses for this Code

We originally figured all this out for use with a personalized "tip" system for a rather complex website. As a visitor used the site certain tips would be weighted more than others and thus more likely to be displayed. In this case a default weightings list was modified for each individual visitor.

You could also track usage of, for example, articles read on a site and weight those that visitors rate highly more than others when presenting random selections. Targeted banner ads are another possibility.

Keep in mind that this isn't the speediest code in the world. However it's not the slowest either and should work reliably for small to medium jobs.

19 Current Sessions; Time: 18:00:40 19-11-2008; Tick: 594