Pick unique Random numbers

2019-01-03 00:46发布

I'm trying to randomize a number in VB.NET 3 times. And each time I randomize a number it should be different from the other two numbers.

For example I have 3 integers. Int1,Int2 and Int3. I will randomize Int1 between 1-10 , and then I will randomize Int2 between 1-10 however the value shouldn't be equal to the value I randomized in Int1 and the same goes for Int3 it shouldn't equal to Int1 and Int2.

I have figured out how to randomize a number, this is the code I'm using:

Dim RndNumber As Random
Dim num,num2 As Integer
RndNumber = New Random
num = RndNumber.Next(1, 11)
num2 = RndNumber.Next(1, 11)

Now I'm stuck on how I make num2 randomize a number between 1-10 that is not equals to num.

I appreciate any help, thanks.

1条回答
疯言疯语
2楼-- · 2019-01-03 00:49

In all the examples, RNG is a random number generator created from the NET Random class:

Private RNG = New Random()

Linq

If you only need two or three, you could loop until the current pick is not in the result set. But this is even simpler using some extension methods:

Dim nums = Enumerable.Range(1, 10).
                OrderBy(Function(r) RNG.Next).
                Take(3).
                ToArray()

This starts with all numbers between 1 and 10, puts them in random order, takes the first 3 and stores them in the nums array. I used the multiline form, breaking after the .s to illustrate the steps.

Just change the range, size/count and Take() element as needed. For instance, for something like a lottery with 5 unique numbers 1-69 (condensed form):

Dim winners = Enumerable.Range(1, 69).OrderBy(Function(r) RNG.Next()).Take(5).ToArray()
Dim powerball = Enumerable.Range(1, 26).OrderBy(Function(r) RNG.Next()).Take(1).First

Since the Powerball can be a repeat of the first numbers, it comes from its own pool. Since we only want one, we dont need an array, just the First().

Manual

It is good to know the logic for these things, so this shows a manual version. This does it differently, by picking and actually checking random values:

' picked value storage
Dim picks As New List(Of Int32)

Dim pick As Int32          ' current candidate
Do
    pick = RNG.Next(1, 11)
    If picks.Contains(pick) = False Then
        picks.Add(pick)
    End If
Loop Until picks.Count = 3

Rather than loose vars, this uses a list to hold the picks. This makes it easy to see if the current pick has already been selected. For more than just a few values, use a HashSet(Of Int32) rather than a List for performance.

Random Pairs

To create a random sets of numbers with 2 of each, such as for a matching game, just double up the base pool of values then put them in random order:

' create pool of 2 values each for 1-13
Dim nums = Enumerable.Range(1, 13).ToArray()
' concat the set to make 2 of each value, randomize 
Dim pool = nums.Concat(nums).OrderBy(Function(r) RNG.Next).ToArray()

For a manual method you would have to check the count of each value in the loop.

'Use up' Picks

One more variation is when you need a pool of randoms used periodically, but you don't know how many you will need in advance. Examples would be the balls for a BINGO game or a deck of cards.

Rather than a global indexer pointing to the last slot used (or next slot to use), a Stack(Of T) (or a Queue) will "use up" values as you need them:

' create, randomize pool of 100 ints
Dim nums = Enumerable.Range(1, 100).OrderBy(Function(r) RNG.Next).ToArray
' use array to create Stack<T>
Dim shoe As New Stack(Of Int32)(nums)

' same as:
Dim shoe = New Stack(Of Int32)(Enumerable.Range(1, 100).
                                OrderBy(Function(r) RNG.Next).ToArray())

This starts basically the same with 100 integers, randomized and stored in an array, but there is no Take(n) because we want them all. They values are then stored in a stack collection. Using it:

Console.WriteLine(shoe.Count)
For n As Int32 = 1 To 3
    Console.WriteLine("Picked #{0}", shoe.Pop)
Next
Console.WriteLine(shoe.Count)

When you Pop a value it is removed from the collection automatically. If you use a lot of values from the shoe, you will want to check the count to make sure it is not empty.

100
Picked #12
Picked #69
Picked #53
97

After drawing 3 values, the shoe has only 97 values remaining.

Random Notes

In all cases your Random generator should be a form level object which you create once. Never create them in a loop or you will likely get the same value over and over.

The OrderBy(Function(r) RNG.Next) method of randomizing is usually good enough for casual use, but it is inefficient. If you will be randomizing large sets and/or using it frequently you should consider using a proper shuffle such as the Fisher-Yates shuffle shown here.

查看更多
登录 后发表回答