|
-
May 23rd, 2013, 11:46 AM
#1
Thread Starter
Lively Member
[RESOLVED] Randomly selected item from list which have a %
Basically, I know how to get a random number but I'm not sure how to select an item from a list which has a percentage of being randomly selected.
EG. If this is my list
Red - 10%
Blue - 25%
Green - 7%
Yellow - 58%
I then declare a random which selects an item based off their percentage. So yellow is likely to be selected and green the least likely.
How would I go around doing that.
[RESOLVED]
I used some of these posts solutions and wrote the code myself. Its minimal which i like and it works on bigger decimal probabilities.
Code:
Dim useRandom As New Random
Select Case (Math.Round(useRandom.NextDouble(), 2))
Case 0 To 0.25
MsgBox("Red")
Case 0.26 To 0.5
MsgBox("Blue")
Case 0.51 To 0.75
MsgBox("Green")
Case 0.76 To 1
MsgBox("Yellow")
End Select
Last edited by xx_dan_xx; May 24th, 2013 at 09:24 AM.
-
May 23rd, 2013, 11:57 AM
#2
Re: Randomly selected item from list which have a %
Select a random number from 1 to 100, then use a select case. 1-10 is Red, 11-35 is Blue and so on.
As the 6-dimensional mathematics professor said to the brain surgeon, "It ain't Rocket Science!"
Reviews: "dunfiddlin likes his DataTables" - jmcilhinney
Please be aware that whilst I will read private messages (one day!) I am unlikely to reply to anything that does not contain offers of cash, fame or marriage!
-
May 23rd, 2013, 12:01 PM
#3
Thread Starter
Lively Member
Re: Randomly selected item from list which have a %
Yeah I had that idea but for some reason I thought they may of been a easier way because I'll have to figure out what number ranges equals what % because some get really small. Thanks
-
May 23rd, 2013, 12:10 PM
#4
Re: Randomly selected item from list which have a %
It's just adding up.
1 to P1
P1+1 to P1 + P2
P1+P2+1 to P1+P2+P3
If you have fractional percentages (eg. 30.5% then multiply everything by 10 as many times as it takes to make all the values integers)
As the 6-dimensional mathematics professor said to the brain surgeon, "It ain't Rocket Science!"
Reviews: "dunfiddlin likes his DataTables" - jmcilhinney
Please be aware that whilst I will read private messages (one day!) I am unlikely to reply to anything that does not contain offers of cash, fame or marriage!
-
May 23rd, 2013, 12:40 PM
#5
Re: Randomly selected item from list which have a %
What is done in role playing board/computer games is a dice is rolled to determine an outcome. JMcIlhinney has a code bank post here that is a Die(singular of dice) class. I would be tempted to use that.
-
May 23rd, 2013, 01:08 PM
#6
Re: Randomly selected item from list which have a %
here's my attempt at a solution:
Code:
Imports System.Text.RegularExpressions
Public Class Form1
Dim r As New Random
Dim colors As New Dictionary(Of Integer, String)
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
colors.Add(7, "Green")
colors.Add(10, "Red")
colors.Add(25, "Blue")
colors.Add(58, "Yellow")
ListBox1.Items.AddRange(Array.ConvertAll(colors.Values.ToArray, Function(s) s & " (0)"))
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
For y As Integer = 1 To 10000
Dim x As Integer = r.Next(1, 1451)
Dim listIndex As Integer
'/7 = 1450
'/10 = 1015
'/25 = 406
'/58 = 175
Select Case x
Case Is > 1015
listIndex = r.Next(0, 4)
Case Is > 406
listIndex = r.Next(1, 4)
Case Is > 175
listIndex = r.Next(2, 4)
Case Is > 0
listIndex = 3
End Select
Dim rx As New Regex("(Red|Blue|Green|Yellow)\s\((\d+)\)")
ListBox1.Items(listIndex) = Regex.Replace(ListBox1.Items(listIndex).ToString, rx.ToString, "$1 (" & (CInt(rx.Match(ListBox1.Items(listIndex).ToString).Groups(2).Value) + 1).ToString & ")")
Next
End Sub
End Class
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
-
May 23rd, 2013, 01:21 PM
#7
Re: Randomly selected item from list which have a %
 Originally Posted by dday9
What is done in role playing board/computer games is a dice is rolled to determine an outcome. JMcIlhinney has a code bank post here that is a Die(singular of dice) class. I would be tempted to use that.
How is that different to getting a random number from 1 to 100?
As the 6-dimensional mathematics professor said to the brain surgeon, "It ain't Rocket Science!"
Reviews: "dunfiddlin likes his DataTables" - jmcilhinney
Please be aware that whilst I will read private messages (one day!) I am unlikely to reply to anything that does not contain offers of cash, fame or marriage!
-
May 23rd, 2013, 01:22 PM
#8
Re: Randomly selected item from list which have a %
here's my attempt at a solution:
Have you been at the Horlick's again?
As the 6-dimensional mathematics professor said to the brain surgeon, "It ain't Rocket Science!"
Reviews: "dunfiddlin likes his DataTables" - jmcilhinney
Please be aware that whilst I will read private messages (one day!) I am unlikely to reply to anything that does not contain offers of cash, fame or marriage!
-
May 23rd, 2013, 01:30 PM
#9
Re: Randomly selected item from list which have a %
 Originally Posted by dunfiddlin
How is that different to getting a random number from 1 to 100?
It's all the same, just a different spin on it. I personally prefer the rolling a die method, somebody else may prefer the method you presented.
-
May 23rd, 2013, 01:31 PM
#10
Re: Randomly selected item from list which have a %
ok. maybe there's a better solution.
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
-
May 23rd, 2013, 01:33 PM
#11
Re: Randomly selected item from list which have a %
 Originally Posted by dday9
It's all the same, just a different spin on it. I personally prefer the rolling a die method, somebody else may prefer the method you presented.
Maybe I am just being dense, but how does the roll of a die work in this case?
-
May 23rd, 2013, 01:37 PM
#12
Re: Randomly selected item from list which have a %
 Originally Posted by dbasnett
Maybe I am just being dense, but how does the roll of a die work in this case?
it doesn't strictly speaking. Those of us that can remember the heyday of board games that used actual boards will be familiar with percentage dice, two dice of differing colours numbered 0 - 9. You'd roll them and take the red one as tens, and the blue as units, for example, to get a number from 00 - 99.
As the 6-dimensional mathematics professor said to the brain surgeon, "It ain't Rocket Science!"
Reviews: "dunfiddlin likes his DataTables" - jmcilhinney
Please be aware that whilst I will read private messages (one day!) I am unlikely to reply to anything that does not contain offers of cash, fame or marriage!
-
May 23rd, 2013, 01:42 PM
#13
Re: Randomly selected item from list which have a %
 Originally Posted by dunfiddlin
 Have you been at the Horlick's again?
I reckon you should post a proveable solution...
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
-
May 23rd, 2013, 01:47 PM
#14
Re: Randomly selected item from list which have a %
Isn't Horlick's a suspension rather than a solution?
As the 6-dimensional mathematics professor said to the brain surgeon, "It ain't Rocket Science!"
Reviews: "dunfiddlin likes his DataTables" - jmcilhinney
Please be aware that whilst I will read private messages (one day!) I am unlikely to reply to anything that does not contain offers of cash, fame or marriage!
-
May 23rd, 2013, 02:04 PM
#15
Re: Randomly selected item from list which have a %
 Originally Posted by dunfiddlin
it doesn't strictly speaking. Those of us that can remember the heyday of board games that used actual boards will be familiar with percentage dice, two dice of differing colours numbered 0 - 9. You'd roll them and take the red one as tens, and the blue as units, for example, to get a number from 00 - 99.
Ten sided die? What about the other colors the OP mentioned?
-
May 23rd, 2013, 03:04 PM
#16
Re: Randomly selected item from list which have a %
Yup 10 sided.

I've still got a couple of pairs knocking around somewhere. You could also get 12 and 20 sided though I never personally found a use for them.
As the 6-dimensional mathematics professor said to the brain surgeon, "It ain't Rocket Science!"
Reviews: "dunfiddlin likes his DataTables" - jmcilhinney
Please be aware that whilst I will read private messages (one day!) I am unlikely to reply to anything that does not contain offers of cash, fame or marriage!
-
May 23rd, 2013, 03:35 PM
#17
Thread Starter
Lively Member
Re: Randomly selected item from list which have a %
Colours were an example. I have a list of 20+ items each assigned a percentage. Then a random is used to return one of those items based of the percentage and some % are below 1. Would be inefficient I think to use dice.
-
May 23rd, 2013, 03:43 PM
#18
Re: Randomly selected item from list which have a %
Code:
Dim greens() As Integer = Enumerable.Range(0, 7).Select(Function(i) 0).ToArray 'seven elements of one hundred assigned value 0
Dim reds() As Integer = Enumerable.Range(0, 10).Select(Function(i) 1).ToArray 'ten elements of one hundred assigned value 1
Dim blues() As Integer = Enumerable.Range(0, 25).Select(Function(i) 2).ToArray 'twenty five elements of one hundred assigned value 2
Dim yellows() As Integer = Enumerable.Range(0, 58).Select(Function(i) 3).ToArray 'fifty eight elements of one hundred assigned value 3
Dim possibles() As Integer = greens.Concat(reds).Concat(blues).Concat(yellows).ToArray 'join the four arrays
Dim x As Integer = r.Next(0, 100) 'pick a random number 0 to 99
Dim listIndex As Integer = possibles(x) 'listIndex will equal 0, 1, 2, or 3 with a 7% chance of 0, 10% chance of 1, 25% chance of 2, + 58% chance of 3
edit: to make it more random:
Code:
possibles = possibles.OrderBy(Function(i) r.NextDouble).ToArray
Last edited by .paul.; May 23rd, 2013 at 03:52 PM.
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
-
May 23rd, 2013, 03:53 PM
#19
Re: Randomly selected item from list which have a %
 Originally Posted by xx_dan_xx
Colours were an example. I have a list of 20+ items each assigned a percentage. Then a random is used to return one of those items based of the percentage and some % are below 1. Would be inefficient I think to use dice.
Do the percentages add up to 100%?
-
May 23rd, 2013, 04:01 PM
#20
Thread Starter
Lively Member
Re: Randomly selected item from list which have a %
 Originally Posted by dbasnett
Do the percentages add up to 100%?
Yes they do. And ill take a look at that paul thanks.
-
May 24th, 2013, 01:41 AM
#21
Thread Starter
Lively Member
Re: Randomly selected item from list which have a %
Paul haven't had time to test it since I had exams yesterday and today but I'm not sure that would work for decimal percentages. For instance I have a percentage at 0.20%.
-
May 24th, 2013, 03:33 AM
#22
Re: Randomly selected item from list which have a %
Here's a class that will do the job for you:
Code:
''' <summary>
''' Generates random values from a list with weighted likelihoods.
''' </summary>
''' <typeparam name="T">
''' The type of the items to be selected.
''' </typeparam>
Public Class WeightedRandom(Of T)
''' <summary>
''' The random number generator.
''' </summary>
''' <remarks>
''' There is one instance for all instances of the class.
''' </remarks>
Private Shared rng As New Random
''' <summary>
''' Values keyed on the maximum weight for which they will be selected.
''' </summary>
Private ReadOnly valuesByWeightThreshold As New Dictionary(Of Integer, T)
''' <summary>
''' The weights of all values summed.
''' </summary>
Private ReadOnly totalWeight As Integer
''' <summary>
''' Initialises a new instance of the <see cref="WeightedRandom(Of T)"/> class.
''' </summary>
''' <param name="weightsByValue">
''' A list of values and the weights for each one.
''' </param>
Public Sub New(weightsByValue As IDictionary(Of T, Integer))
Dim rollingWeight As Integer
For Each key In weightsByValue.Keys
'Get the weight for all values up to and including this one.
rollingWeight += weightsByValue(key)
'Add the value against that summed weight.
valuesByWeightThreshold.Add(rollingWeight, key)
Next
'Random numbers will be generated less than the total weight.
totalWeight = rollingWeight
End Sub
''' <summary>
''' Gets the next random value.
''' </summary>
''' <returns>
''' A value based on a weighted random selection
''' </returns>
Public Function NextValue() As T
'Generate a random number in the range specified by the combined weights.
Dim number = rng.Next(totalWeight)
Dim value As T
'Find the first weight threshold that is greater than
'the generated number and return the corresponding value.
For Each weight In valuesByWeightThreshold.Keys
If number < weight Then
value = valuesByWeightThreshold(weight)
Exit For
End If
Next
Return value
End Function
End Class
Using your colours and weights from post #1, here's a usage sample:
Code:
Dim weightsByValue As New Dictionary(Of Color, Integer) From {{Color.Red, 10},
{Color.Blue, 25},
{Color.Green, 7},
{Color.Yellow, 58}}
Dim colourGenerator As New WeightedRandom(Of Color)(weightsByValue)
Dim redCount As Integer
Dim blueCount As Integer
Dim greenCount As Integer
Dim yellowCount As Integer
For i = 1 To 100
Select Case colourGenerator.NextValue()
Case Color.Red
redCount += 1
Case Color.Blue
blueCount += 1
Case Color.Green
greenCount += 1
Case Color.Yellow
yellowCount += 1
End Select
Next
MessageBox.Show(String.Format("Reds:{1}{0}Blues:{2}{0}Greens:{3}{0}Yellows:{4}",
Environment.NewLine,
redCount,
blueCount,
greenCount,
yellowCount))
Run that a few times and you'll see that the results are, as you would expect, around about the weights specified but not quite and they are a bit different each time.
That class has a few benefits:
1. You define the values and their weights once and then you don't have to think about them again.
2. You simply call a method and get back one of the values without having to worry about manipulating any numbers.
3. The same class can be used with objects of any type in a list of any length.
4. The weights don't have to add up to 100. They can be anything you like.
Last edited by jmcilhinney; May 24th, 2013 at 03:37 AM.
-
May 24th, 2013, 03:34 AM
#23
Re: Randomly selected item from list which have a %
Just note that that constructor doesn't prevent zero or negative weights being used or total weights greater than Int32.MaxValue. I had to leave a bit of work for someone else.
-
May 24th, 2013, 08:39 AM
#24
Thread Starter
Lively Member
Re: Randomly selected item from list which have a %
 Originally Posted by .paul.
Code:
Dim greens() As Integer = Enumerable.Range(0, 7).Select(Function(i) 0).ToArray 'seven elements of one hundred assigned value 0
Dim reds() As Integer = Enumerable.Range(0, 10).Select(Function(i) 1).ToArray 'ten elements of one hundred assigned value 1
Dim blues() As Integer = Enumerable.Range(0, 25).Select(Function(i) 2).ToArray 'twenty five elements of one hundred assigned value 2
Dim yellows() As Integer = Enumerable.Range(0, 58).Select(Function(i) 3).ToArray 'fifty eight elements of one hundred assigned value 3
Dim possibles() As Integer = greens.Concat(reds).Concat(blues).Concat(yellows).ToArray 'join the four arrays
Dim x As Integer = r.Next(0, 100) 'pick a random number 0 to 99
Dim listIndex As Integer = possibles(x) 'listIndex will equal 0, 1, 2, or 3 with a 7% chance of 0, 10% chance of 1, 25% chance of 2, + 58% chance of 3
edit: to make it more random:
Code:
possibles = possibles.OrderBy(Function(i) r.NextDouble).ToArray
That works for whole numbers but I have decimal percentages. EG (0.25%, 14.3%, etc.) Is there another method than random to pick randomly.
-
May 24th, 2013, 09:00 AM
#25
Re: Randomly selected item from list which have a %
Wasn't something like this suggested?
Code:
Dim d As Double = prng.NextDouble()
Select Case d
Case Is <= 0.0025
Case Is <= 0.01
Case Is <= 0.143
Case Is <= 0.25
Case Is <= 0.58
End Select
Also, jmc's (aka jim) code can probably be modified to use doubles instead of integers.
-
May 24th, 2013, 09:13 AM
#26
Re: Randomly selected item from list which have a %
you just need to scale it up:
Code:
Dim greens() As Integer = Enumerable.Range(0, 730).Select(Function(i) 0).ToArray 'seven hundred + thirty elements of ten thousand (7.3%) assigned value 0
Dim reds() As Integer = Enumerable.Range(0, 1025).Select(Function(i) 1).ToArray 'one thousand + twenty five elements of ten thousand (10.25%) assigned value 1
Dim blues() As Integer = Enumerable.Range(0, 2545).Select(Function(i) 2).ToArray 'two thousand five hundred + forty five elements of ten thousand (25.45%) assigned value 2
Dim yellows() As Integer = Enumerable.Range(0, 5700).Select(Function(i) 3).ToArray 'five thousand seven hundred elements of ten thousand (57%) assigned value 3
Dim possibles() As Integer = greens.Concat(reds).Concat(blues).Concat(yellows).ToArray 'join the four arrays
possibles = possibles.OrderBy(Function(i) r.NextDouble).ToArray
Dim x As Integer = r.Next(0, 10000) 'pick a random number 0 to 9999
Dim listIndex As Integer = possibles(x) 'listIndex will equal 0, 1, 2, or 3 with a 7.3% chance of 0, 10.25% chance of 1, 25.45% chance of 2, + 57% chance of 3
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
-
May 24th, 2013, 09:14 AM
#27
Thread Starter
Lively Member
Re: Randomly selected item from list which have a %
I finally came up with my own solution using your guys ideas. It would support decimal percentages to huge decimal places, random and short.
Code:
Dim useRandom As New Random
Select Case (Math.Round(useRandom.NextDouble(), 2))
Case 0 To 0.25
MsgBox("Red")
Case 0.26 To 0.5
MsgBox("Blue")
Case 0.51 To 0.75
MsgBox("Green")
Case 0.76 To 1
MsgBox("Yellow")
End Select
-
May 24th, 2013, 09:17 AM
#28
Re: Randomly selected item from list which have a %
 Originally Posted by xx_dan_xx
That works for whole numbers but I have decimal percentages. EG (0.25%, 14.3%, etc.) Is there another method than random to pick randomly.
You do realise that you can simply multiply those decimals by factors of 10 and they become whole numbers, right? If the largest number of decimal places is 2 then you simply multiple everything by 100 . You can then use .paul.'s suggestion or mine as is. That said, here's my WeightedRandom class adapted to use Doubles:
Code:
''' <summary>
''' Generates random values from a list with weighted likelihoods.
''' </summary>
''' <typeparam name="T">
''' The type of the items to be selected.
''' </typeparam>
Public Class WeightedRandom(Of T)
''' <summary>
''' The random number generator.
''' </summary>
''' <remarks>
''' There is one instance for all instances of the class.
''' </remarks>
Private Shared rng As New Random
''' <summary>
''' Values keyed on the maximum weight for which they will be selected.
''' </summary>
Private ReadOnly valuesByWeightThreshold As New Dictionary(Of Double, T)
''' <summary>
''' The weights of all values summed.
''' </summary>
Private ReadOnly totalWeight As Double
''' <summary>
''' Initialises a new instance of the <see cref="WeightedRandom(Of T)"/> class.
''' </summary>
''' <param name="weightsByValue">
''' A list of values and the weights for each one.
''' </param>
Public Sub New(weightsByValue As IDictionary(Of T, Double))
Dim rollingWeight As Double
For Each key In weightsByValue.Keys
'Get the weight for all values up to and including this one.
rollingWeight += weightsByValue(key)
'Add the value against that summed weight.
valuesByWeightThreshold.Add(rollingWeight, key)
Next
'Random numbers will be generated less than the total weight.
totalWeight = rollingWeight
End Sub
''' <summary>
''' Gets the next random value.
''' </summary>
''' <returns>
''' A value based on a weighted random selection
''' </returns>
Public Function NextValue() As T
'Generate a random number in the range specified by the combined weights.
Dim number = rng.NextDouble() * totalWeight
Dim value As T
'Find the first weight threshold that is greater than
'the generated number and return the corresponding value.
For Each weight In valuesByWeightThreshold.Keys
If number < weight Then
value = valuesByWeightThreshold(weight)
Exit For
End If
Next
Return value
End Function
End Class
The sample usage is exactly the same except that the Dictionary values are type Double instead of type Integer, e.g.
Code:
'Proportional weightings of 1:38:20:51.
Dim weightsByValue As New Dictionary(Of Color, Double) From {{Color.Red, 0.25},
{Color.Blue, 9.5},
{Color.Green, 5},
{Color.Yellow, 12.75}}
Dim colourGenerator As New WeightedRandom(Of Color)(weightsByValue)
Dim redCount As Integer
Dim blueCount As Integer
Dim greenCount As Integer
Dim yellowCount As Integer
For i = 1 To 100
Select Case colourGenerator.NextValue()
Case Color.Red
redCount += 1
Case Color.Blue
blueCount += 1
Case Color.Green
greenCount += 1
Case Color.Yellow
yellowCount += 1
End Select
Next
MessageBox.Show(String.Format("Reds:{1}{0}Blues:{2}{0}Greens:{3}{0}Yellows:{4}",
Environment.NewLine,
redCount,
blueCount,
greenCount,
yellowCount))
Sub
-
May 24th, 2013, 09:19 AM
#29
Thread Starter
Lively Member
Re: Randomly selected item from list which have a %
I found a different method, which isminimal and that would require more lines of code when I already have a solution which is small.
-
May 24th, 2013, 09:24 AM
#30
Re: Randomly selected item from list which have a %
 Originally Posted by xx_dan_xx
I found a different method, which isminimal and that would require more lines of code when I already have a solution which is small.
You "found" a solution that just happens to be almost exactly what was suggested in post #2 nearly 24 hours ago. Anyway, I'm not saying that mine is the only or even the best solution but what it does do is create a reusable class so, once that exists, you have to write very little code to use it, plus it can be used to select values of any type. VB is an OO language for a reason so making use of that is rarely a bad thing.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|