Introduction
Generating a random number is quite easy in C# but if you need to pick a winner from a list based on different chances for different participants, you'll need to do more than just generating some random numbers.
Here is a generic class allowing you to define a lottery and add tickets with different weights (or equal). By calling the Draw()
method, you'll get the next winner. The removeWinner
parameter specifies whether the winner will be removed from the list or not.
Math
Assume all tickets are in an array called tickets[]
and every ticket has a weight of w
and the sum of all weights in the array is stored in sum
, then the probability of each ticket (ticket.p
) is:
tickets[i].p = tickets[i].w / sum
Using the Code
Copy the following class into your solution:
public class Lottery<T>
{
public class Ticket
{
public T Key { get; private set; }
public double Weight { get; private set; }
public Ticket(T key, double weight)
{
this.Key = key;
this.Weight = weight;
}
}
List<Ticket> tickets = new List<Ticket>();
static Random rand = new Random();
public void Add(T key, double weight)
{
tickets.Add(new Ticket(key, weight));
}
public Ticket Draw(bool removeWinner)
{
double r = rand.NextDouble() * tickets.Sum(a => a.Weight);
double min = 0;
double max = 0;
Ticket winner = null;
foreach (var ticket in tickets)
{
max += ticket.Weight;
if (min <= r && r < max)
{
winner = ticket;
break;
}
min = max;
}
if (winner == null) throw new Exception();
if (removeWinner) tickets.Remove(winner);
return winner;
}
}
And use it like:
var lottery = new Lottery<string>();
lottery.Add("Mr. A", 1);
lottery.Add("Ms. B", 2);
lottery.Add("Ms. C", 3);
var winner = lottery.Draw(true);