Skip to content

Instantly share code, notes, and snippets.

@RobThree
Last active August 3, 2016 13:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RobThree/2626a5c6599fc60c6e3025a4e46bacd0 to your computer and use it in GitHub Desktop.
Save RobThree/2626a5c6599fc60c6e3025a4e46bacd0 to your computer and use it in GitHub Desktop.
"Weighted random" object picker (based on http://www.perlmonks.org/?node_id=242751)
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
// Demo
static void Main(string[] args)
{
// Define some weighted object (in this case: strings, but could be anything (e.g. "Customer") and set their weights
var myobjects = new[]
{
new WeightedObject<string>("A", 2),
new WeightedObject<string>("B", 3),
new WeightedObject<string>("C", 5),
new WeightedObject<string>("D", 10)
};
// For <iterations> iterations pick a random object from the above array; keep track of the results in a list
var iterations = 10000;
var results = new List<WeightedObject<string>>();
for (int i = 0; i < iterations; i++)
results.Add(WeightedObjectPicker.PickWeightedObject(myobjects));
// Print the number of times each object was picked and also present this as a percentage
Console.WriteLine(
string.Join("\r\n", results.GroupBy(o => o.Object).OrderBy(g => g.Key).Select(g => $"{g.Key}\t{g.Count()}\t{(double)g.Count() / iterations:P2}%"))
);
}
}
// Picks 'weighted random' objects from an array of objects
public class WeightedObjectPicker
{
// Initialize RNG
private static readonly Random rng = new Random();
public static WeightedObject<T> PickWeightedObject<T>(WeightedObject<T>[] objects)
{
// Initialize indexer to point to first object in array, get total weight of objects, pick random number below total weight
int i = 0, totalweight = objects.Sum(o => o.Weight), r = rng.Next(totalweight);
// Note: we may want to check totalweight to be greater than 0
// While the random number >= 0
while (r >= 0)
r -= objects[i++].Weight; // Subtract indexed object's weight, increase indexer
// Decrease indexer by one (we incremented it one time too many) and return indexed object
return objects[--i];
}
}
// Represents a weighted object of type T
public class WeightedObject<T>
{
// The object's weight
public int Weight { get; private set; }
// The object
public T Object { get; private set; }
// Initialize new weighted object of T with it's weight
public WeightedObject(T obj, int weight)
{
if (weight < 0)
throw new ArgumentOutOfRangeException("Weight must be >= 0");
this.Object = obj;
this.Weight = weight;
}
}
A 1023 10,23 %%
B 1530 15,30 %%
C 2497 24,97 %%
D 4950 49,50 %%
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment