שתף באמצעות


Random number generator without repeating

Question

Tuesday, November 1, 2016 12:20 AM

I am coding a test simulator with picture actually. I found an easier way to create a random number generator without repeating.

Here is my code:

Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim RandomClass As New Random()
        Dim RememberSet As New HashSet(Of Integer)

        Dim RandomNumber As Integer

        While RememberSet.Count < 10
            RandomNumber = RandomClass.Next(1, 11)
            If RememberSet.Add(RandomNumber) Then
                ListBox1.Items.Add(RandomNumber)
            End If
        End While
        Button1.Visible = False
    End Sub
End Class

But I've a question now, the number don't repeat. But does VB has a function to select row in the listbox?

No matter first row is number 3 or 10, but we can select the item in the first row like using

ListBox1.SelectedRow1

Or there is another way to do random generator without repeating?

All replies (7)

Tuesday, November 1, 2016 12:48 AM ✅Answered

I am coding a test simulator with picture actually. I found an easier way to create a random number generator without repeating.

Here is my code:

Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim RandomClass As New Random()
        Dim RememberSet As New HashSet(Of Integer)

        Dim RandomNumber As Integer

        While RememberSet.Count < 10
            RandomNumber = RandomClass.Next(1, 11)
            If RememberSet.Add(RandomNumber) Then
                ListBox1.Items.Add(RandomNumber)
            End If
        End While
        Button1.Visible = False
    End Sub
End Class

But I've a question now, the number don't repeat. But does VB has a function to select row in the listbox?

No matter first row is number 3 or 10, but we can select the item in the first row like using

ListBox1.SelectedRow1

Or there is another way to do random generator without repeating?

Hi

Here is one way - this will display a unique random and show selected item in a label.

' Form1 with
'  ListBox1
'  TextBox1, TextBox2, TextBox3 
'  Button1, Label1

' TextBox1 for How Many to make
' TextBox2 for Large number
' TextBox3 for Smallest number
' Label1 displays selected item value (as string)

' no error checking included
Option Strict On
Option Infer Off
Option Explicit On
Public Class Form1
    Private rand As New Random
    Function GetRand(smallest As Integer, largest As Integer, tk As Integer) As List(Of Integer)
        ' returns list of unique randoms between smallest to
        ' (smallest + largest)
        Return Enumerable.Range(smallest, largest).OrderBy(Function(n) rand.Next).Take(tk).ToList
    End Function
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim howmany As Integer = GetInteger(TextBox1.Text)
        Dim largenum As Integer = GetInteger(TextBox2.Text)
        Dim smallnum As Integer = GetInteger(TextBox3.Text)
        ListBox1.DataSource = GetRand(smallnum, largenum, howmany)
    End Sub
    Private Function GetInteger(s As String) As Integer
        Dim v As Integer = 0
        If Integer.TryParse(s, v) Then Return v
        Return 0
    End Function
    Private Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListBox1.SelectedIndexChanged
        Dim lb As ListBox = DirectCast(sender, ListBox)
        Label1.Text = lb.SelectedItem.ToString
    End Sub
End Class

Regards Les, Livingston, Scotland


Tuesday, November 1, 2016 12:37 AM

Select it by using the mouse?

All controls have events and you should use the ListBox selected index changed event and retrieve the ListBox's selected item.

If you click on the ListBox in the designer window it should create a selected changed event in the code window.

ListBox items are type "object" which can be any type. So if you want to use it as a numeric value then you need to convert it to a numeric type when you get it.

Dim i As Integer = CInt(ListBox1.SelectedItem)

Of course the above code will fail and cause the app to crash if the ListBox's selected item can not be converted to an integer value (maybe the item is the word "Hello").

La vida loca


Tuesday, November 1, 2016 12:53 AM

But does VB has a function to select row in the listbox?

You can set the current selection of a listbox to any 'row', and you can get the item from that current selected row.

        ListBox1.SelectedIndex = 1
        Label1.Text = ListBox1.SelectedItem.ToString

Tuesday, November 1, 2016 1:04 AM | 1 vote

Or there is another way to do random generator without repeating?

The easiest and shortest way is to create a list and, per instance, remove from that list as you're going.

For example:

Option Strict On
Option Explicit On
Option Infer Off

Public Class Form1
    Private rand As New Random

    Private Sub Form1_Load(sender As System.Object, _
                           e As System.EventArgs) _
                           Handles MyBase.Load

        Dim strings() As String = _
            {"this", "that", "the other"}

        Dim randomStrings() As String = _
            GetRandomStrings(strings)

        Stop

    End Sub

    Private Function _
        GetRandomStrings(ByVal strings As IEnumerable(Of String)) As String()

        Dim retVal() As String = Nothing

        If strings IsNot Nothing AndAlso strings.Count > 0 Then
            Dim sList As New List(Of String)

            For Each s As String In strings
                sList.Add(s)
            Next

            Dim resultList As New List(Of String)

            Do While sList.Count > 0
                Dim idx As Integer = rand.Next(0, sList.Count)

                resultList.Add(sList(idx))
                sList.RemoveAt(idx)
            Loop

            retVal = resultList.ToArray
        End If

        Return retVal

    End Function

End Class

"Everybody in this country should learn how to program a computer... because it teaches you how to think." (Steve Jobs)


Tuesday, November 1, 2016 10:54 PM

I am coding a test simulator with picture actually. I found an easier way to create a random number generator without repeating.

Here is my code:

Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim RandomClass As New Random()
        Dim RememberSet As New HashSet(Of Integer)

        Dim RandomNumber As Integer

        While RememberSet.Count < 10
            RandomNumber = RandomClass.Next(1, 11)
            If RememberSet.Add(RandomNumber) Then
                ListBox1.Items.Add(RandomNumber)
            End If
        End While
        Button1.Visible = False
    End Sub
End Class

But I've a question now, the number don't repeat. But does VB has a function to select row in the listbox?

No matter first row is number 3 or 10, but we can select the item in the first row like using

ListBox1.SelectedRow1

Or there is another way to do random generator without repeating?

Hi

Here is one way - this will display a unique random and show selected item in a label.

' Form1 with
'  ListBox1
'  TextBox1, TextBox2, TextBox3 
'  Button1, Label1

' TextBox1 for How Many to make
' TextBox2 for Large number
' TextBox3 for Smallest number
' Label1 displays selected item value (as string)

' no error checking included
Option Strict On
Option Infer Off
Option Explicit On
Public Class Form1
    Private rand As New Random
    Function GetRand(smallest As Integer, largest As Integer, tk As Integer) As List(Of Integer)
        ' returns list of unique randoms between smallest to
        ' (smallest + largest)
        Return Enumerable.Range(smallest, largest).OrderBy(Function(n) rand.Next).Take(tk).ToList
    End Function
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim howmany As Integer = GetInteger(TextBox1.Text)
        Dim largenum As Integer = GetInteger(TextBox2.Text)
        Dim smallnum As Integer = GetInteger(TextBox3.Text)
        ListBox1.DataSource = GetRand(smallnum, largenum, howmany)
    End Sub
    Private Function GetInteger(s As String) As Integer
        Dim v As Integer = 0
        If Integer.TryParse(s, v) Then Return v
        Return 0
    End Function
    Private Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListBox1.SelectedIndexChanged
        Dim lb As ListBox = DirectCast(sender, ListBox)
        Label1.Text = lb.SelectedItem.ToString
    End Sub
End Class

Regards Les, Livingston, Scotland

What if I want to generate it one by one but also without repeating?


Tuesday, November 1, 2016 11:27 PM

Hi

If you want to use one by one, then one way is to generate a large list of unique randoms, then, as you use them, remove from the list.

For example: you generate a list of 500 unique randoms. You start at the first one in the list. Assign it to the varriable you are going to use, and remove from the list - the next on - still position 1 in the list is available for use - use it. Here is an example

Option Strict On
Option Infer Off
Option Explicit On
Public Class Form1
    Dim rand As New Random
    Dim MasterList As New List(Of Integer)
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ' get a 500 list of unique randoms
        ' between 10 and 1000

        ' from     - to -    how many
        '  10      10+991-1    500
        MasterList = GetRand(10, 991, 500)

        'now you have 500 unique randoms

        ' use the first one and remove it from list
        ' make sure you have a list that is longer
        ' than the number of likely used randoms 
        ' OR, you must deal with things if the list
        ' runs out of randoms.
        Dim mynumber As Integer = MasterList(0)
        MasterList.RemoveAt(0)

    End Sub

    Function GetRand(smallest As Integer, largest As Integer, tk As Integer) As List(Of Integer)
        ' returns list of unique randoms between smallest to
        ' (smallest + largest)
        Return Enumerable.Range(smallest, largest).OrderBy(Function(n) rand.Next).Take(tk).ToList
    End Function

End Class

Regards Les, Livingston, Scotland


Tuesday, November 1, 2016 11:38 PM

$0.02

Public Class Form1

    Private Shared prng As New Random

    Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
        LoadLB()
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Label1.Text = TakeOne.ToString
    End Sub

    Private lbItms As List(Of Object)
    Const StartAt As Integer = 1 'start here
    Const HowMany As Integer = 10 'StartAt for this count

    Private Sub LoadLB()
        If lbItms Is Nothing OrElse lbItms.Count = 0 Then
            lbItms = Enumerable.Range(StartAt, HowMany).OrderBy(Function(n) prng.Next).Cast(Of Object)().ToList
        End If
        ListBox1.DataSource = Nothing
        ListBox1.DataSource = lbItms
    End Sub

    Private Function TakeOne() As Integer
        Dim rv As Integer
        Dim idx As Integer = prng.Next(lbItms.Count)
        rv = DirectCast(lbItms(idx), Integer)
        lbItms.RemoveAt(idx)
        LoadLB() 'will reload if empty
        Return rv
    End Function
End Class

"Those who use Application.DoEvents() have no idea what it does and those who know what it does never use it." - MSDN User JohnWein    Multics - An OS ahead of its time.