Question How do I generate an array of 5 random numbers (with no repeates)

Mixelplik

Member
Joined
Dec 12, 2009
Messages
5
Programming Experience
Beginner
I'm trying to make a Bulls and Cows type game, I was able to do it fairly easily with javaScript, but VB is killing me. I can get the array 5 slots long with random numbers, unfortunately they're all repeats. when I try getting no repeats I run into infinite loops, exponentially increasing array lengths, and just plain old arrays with 5 numbers randomly generated, but with repeats.

I'm trying to do this with loops, in JS I did it using regular expressions, but I have no clue how to use them in VB.

Here's an example of my code.

Please note, I'm a beginner - so please be patient. Thanks for anyhelp.

VB.NET:
Public Class Form1
    Dim intRand(0) As Integer

    Dim RandomClass As New Random


    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        ReDim intRand(0)
        intRand(0) = GenNum()
        Dim intTempRand As Integer = 0
        Dim intCounter As Integer = 0
        '     lst5Rand.Items.Clear()

        'Loop Outter
        For i As Integer = 0 To 4
            'Loop Inner
            intTempRand = GenNum()
            For y As Integer = 0 To intRand.Length
                If intTempRand = intRand(y) Then
                    lbl1.Text = "Duplicate"
                    Do While intTempRand = intRand(y)
                        intTempRand = GenNum()
                    Loop
                ElseIf intTempRand <> intRand(y) Then
                    lbl1.Text = Convert.ToString(intRand.Length)
                    ReDim Preserve intRand(intRand.Length + 1)
                    intRand(i + 1) = intTempRand
                End If
                ReDim Preserve intRand(intRand.Length + 1)
            Next
            lst5Rand.Items.Add(intRand(i))

        Next

    End Sub

    Private Function GenNum() As Integer
        Return RandomClass.Next(0, 4)
    End Function


End Class
 
Use the Shuffle Sort algorithm.

Here's how:

VB.NET:
	Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
		Dim x, mix, temp As Integer
		Dim num As Integer = 5
		Dim randarray(num) As Integer
		Dim randnum As New Random()
		For x = 1 To num
			randarray(x) = x
		Next x
		For x = 1 To num
			mix = randnum.Next(1, num + 1)
			temp = randarray(mix)
			randarray(mix) = randarray(x)
			randarray(x) = temp
		Next x
		ListBox1.Items.Clear()
		For x = 1 To num
			ListBox1.Items.Add(randarray(x).ToString)
		Next x
	End Sub
 
Thanks so much that's awesome! I'm sorry I should have mentioned that each of the 5 numbers need to be between 0 and 9. With what you've given me, I think I figure it out from here. Thanks again.
 
VB.NET:
Dim rnd As New Random
Dim list = Enumerable.Range(0, 10).OrderBy(Function() rnd.Next)
 
Wow! Thank you, JohnH. I never knew that.

However, it will output the entire list at once using a For Each loop. How can you select only the first few to list?

For example, the OP only wanted 5 numbers within a range of 1-9. Another example: How do you select only the first 6 in a range of 1-48 (as in Lotto)?
 
Last edited:
You can limit the list to only a selection with the Take extension:
VB.NET:
Dim list = Enumerable.Range(1, 48).OrderBy(Function() rnd.Next).Take(6)
Beware that Linq is a in-memory query, the results is retrieved for each call, so if you for example try to get an item by index, list(0), you will in this random query get a different item each time, which could result in duplicate numbers. Similar with multiple For-Each loops you get a new result set each time. One way to get around this, if you need to, is to append the .ToList extension, to have the results converted to a final List(Of T).
 
Show5UniqueRandoms

Private Sub Show5UniqueRandoms()
Dim n As Integer = 0
Dim C As New Collection
Randomize(Timer)
Do
Try
Dim Data = Rnd()
C.Add(Data, "K" & Data)
n += 1
Catch ex As Exception
End Try
Loop Until n = 5
Dim m As Object
For Each m In C
MsgBox(m)
Next
End Sub

Show5UniqueRandoms
Explaination:

The Collection can not have two items with same key. If same Random number is generated again it will raise the error so n value will not change and item is not added to collection.

2nd Randomize Timer is important other wise always you will receive the same result.
 
Thanks again, JohnH. That information was very helpful.
I wrote a Console app that demonstates how it is implemented:


VB.NET:
Module Module1
	Sub Main()
		Dim ans, ans2 As String, max, num As Integer
		Dim rnd As New Random
		Console.WriteLine("Press Enter after input to repeat listing, any other key for new values")
		Do
			Console.Write(vbCrLf & "Enter a range (up to 20) :  ")
			ans = Console.ReadLine()
			Integer.TryParse(ans, max)
			If max > 20 Or max < 1 Then max = 10
			Console.Write(vbCrLf & "Enter number to include (up to " & max & ") :  ")
			ans = Console.ReadLine()
			Integer.TryParse(ans, num)
			If num > max Or num < 1 Then num = max \ 2
			Dim list = Enumerable.Range(1, max).OrderBy(Function() rnd.Next).Take(num)
			Console.WriteLine()
			Do
				For Each x As Integer In list
					Console.Write(x & "  ")
				Next
				Console.WriteLine(vbCrLf)
				ans = Console.ReadKey(True).KeyChar
			Loop While ans = Chr(13)
			Console.Write("Enter to repeat with other values, any other key to quit...")
			ans2 = Console.ReadKey(True).KeyChar
			Console.WriteLine()
		Loop While ans2 = Chr(13)
		Console.WriteLine()
	End Sub
End Module
 
JohnH:

However, using a For Each loop, I am still required to output the entire sequence at once. I may need to save the values and display them one at a time, for example, in a prize drawing program: Click on a button to retrieve the next random number in the sequence to announce the current winner, then click again for the next winner until the range of numbers in the sequence is exhaused. This would be best done if the random numbers were saved to an array. Is there any way this can be done, other than using the Shuffle Sort algorithm I posted above?
 
I answered my own question, figured out how to save to an array:

VB.NET:
Module Module1
	Sub Main()
		Dim count As Integer
		Dim rnd As New Random
                          Dim randarray(9) As Integer
		Dim list = Enumerable.Range(1, 10).OrderBy(Function() rnd.Next)
		Console.WriteLine()
		count = 0
		For Each x As Integer In list
			Console.Write(x & "  ")
			randarray(count) = x
			count += 1
		Next
		Console.WriteLine(vbCrLf)
		For x As Integer = 0 To 9
			Console.Write(randarray(x) & "  ")
		Next
		Console.ReadLine()
	End Sub
End Module
 
hmm, you can use ToList like I mentioned, or ToArray also :)
 
Very good, JohnH. I prepared the following demo:

But this function is not available in VB 2005. Is it part of LINQ?


VB.NET:
Module Module1
	Sub Main()
		Dim ans As String
		Dim rnd As New Random
		Dim list = Enumerable.Range(1, 10).OrderBy(Function() rnd.Next).ToArray
		Console.WriteLine("Press Enter to reshuffle, any other key to quit...")
		Console.WriteLine()
		For Each x As Integer In list	'without the array
			Console.Write(x & "  ")
		Next x
		Console.WriteLine()
		Do
			list = Enumerable.Range(1, 10).OrderBy(Function() rnd.Next).ToArray
			Console.WriteLine()
			For x As Integer = 0 To 9	'with the array
				Console.Write(list(x) & "  ")
			Next x
			Console.WriteLine()
			ans = Console.ReadKey(True).KeyChar()
		Loop While ans = Chr(13)
		Console.WriteLine()
	End Sub
End Module
 
Yes. Enumerable Class (System.Linq)
Namespace: System.Linq
Assembly: System.Core (in System.Core.dll)

Version Information
.NET Framework
Supported in: 3.5
A simplication of your code:
VB.NET:
Do

Loop While Console.ReadKey(True).Key = ConsoleKey.Enter
 
JohnH,

Thanks for all your input. It has been very helpful. I was wondering where you learned about this function. I tried to look it up in several books but was unable to find any reference to it.
 
What function are you referring to now? Generally I read the MSDN library and stuff on the web.
 
Back
Top