Why my code in VB is not working? - vb.net

So the task is:
Write a program that contains a text box, a list box and a command button. Put a label above the text box that tells the user to type a number from 1 to 10 inside the text box. When the user clicks the command button, check the text box for a valid number and issue an error message box if the number isn't inside the expected range or in case of empty input. If the user entered a valid number, assign it to the integer variable n and use a For...Next loop to accumulate the sum of the first n elements of an array declared with the statement Dim numList() as Integer = {2, 4, 10, 5, 6, 8, 9, 3, 2, 4} Display the sum in the list box.
Private Sub bCom_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bCom.Click
Dim n As Integer = CInt(tNum.Text)
If CDbl(tNum.Text) > 10 Then
MessageBox.Show("Please Enter a Number from 1 to 10")
tNum.Focus()
End If
Dim numList() As Integer = {2, 4, 10, 5, 6, 8, 9, 3, 2, 4}
Dim sum As Integer
For Each n As Integer In numList
sum += n
Next
lOut.Items.Add(sum)
End Sub
End Class

You are using a for each loop instead of a for loop, so you iterate over each element in the array, not just the first n ones.
You should use something like:
For x = 0 To n - 1
sum += numList(x)
Next
Some more problems:
No need to convert the text to double if you already converted it to an integer the line before.
You should use Int32.TryParse in case the user enters something that is not a number.
You just check if the number is greater 10, but not if it is smaller than 1.
If the number is invalid, you display a message to the user, then you just keep going on,
but you should exit your method

As others have stated, you need an indexed For..Loop, not a ForEach loop.
You might also consider moving the "is it a valid number" logic to a separate function.
Public Class Form1
Private Sub btnCompute_Click(sender As System.Object, e As System.EventArgs) Handles btnCompute.Click
'is the number valid?
Dim n As Integer = -1
If IsInputValid(txbInput.Text, n) Then
Dim sum As Integer = 0
'declare an array of numbers
Dim numList() As Integer = {2, 4, 10, 5, 6, 8, 9, 3, 2, 4}
'accumulate the sum of the first N elements of the array
For i As Integer = 0 To n - 1
sum += numList(i)
Next
'refresh the listbox with the sum
lbxOutput.Items.Clear()
lbxOutput.Items.Add(sum.ToString)
Else
MessageBox.Show("Please enter a number between 1 and 10")
End If
End Sub
Private Function IsInputValid(input As String, ByRef validnumber As Integer) As Boolean
'input must be a number between 1 and 10
'if it is valid, assign it to the byref validNumber parameter.
Dim i As Integer = -1
If Integer.TryParse(input, i) Then
If i >= 1 AndAlso i <= 10 Then
validnumber = i
Return True
End If
End If
validnumber = i
Return False
End Function
End Class

If I understand your question correctly, you want to sum the first n digits of the array numList.
If this is the case then you need to change your loop code in this way
For x = 0 To n -1
sum += numList(x)
Next
Use x as the indexer to the numList array, start at the first element of the array (x=0) and stop when the indexer has reached the value of n - 1
With this you could satisfy the requirements exactly how they have been asked.
If you wish you could also show an elegant approach using LinQ without an explict loop
sum = numList.Take(n).Sum()
However, before going fancy, it is better that you remove some obvious errors in your code
if Not Int32.TryParse(tNum.Text, n) Then
MessageBox.Show("Error......")
tNum.Focus()
Return
End If
if n < 1 OrElse n > 10 Then
MessageBox.Show("Error......")
tNum.Focus()
Return
End if
And do not use the old fashioned function like CInt e CDbl that are kept only for compatibility with VB6. Use the newest methods like Int32.TryParse, Convert.ToInt32 etc...

Related

create 1000, 8-character random ID's, all unique and display in a text box

enter image description hereWrite a program to display 1000 8-character random user IDs in a text box after you click a button. Make sure the program verifies that none of the IDs are identical. Each userid should include a mixture of alphabetic characters and numbers.
What I have so far, which could be enough to get by as a random ID generator alone, but it does not loop 1000 times to be displayed in the label, and doesn't check for repeated ID's.
Public Class Form1
Private Sub btnGenerateRandomID_Click(sender As Object, e As EventArgs) Handles btnGenerateRandomID.Click
Dim rand As New Random
Dim char1 As String
Dim char2 As String
Dim char3 As String
Dim char4 As String
Dim char5 As String
Dim char6 As String
Dim char7 As String
Dim char8 As String
char1 = ChrW(rand.Next(Asc("A"), Asc("Z") + 1))
char2 = ChrW(rand.Next(Asc("A"), Asc("Z") + 1))
char3 = ChrW(rand.Next(Asc("A"), Asc("Z") + 1))
char4 = ChrW(rand.Next(Asc("A"), Asc("Z") + 1))
char5 = rand.Next(0, 9)
char6 = rand.Next(0, 9)
char7 = rand.Next(0, 9)
char8 = rand.Next(0, 9)
lblRandomId.Text = char1 + char2 + char3 + char4 + char5 + char6 + char7 + char8
End Sub
End Class
Thanks.
EDIT:
Public Class Form1
'Write a program to display 1000 8-character random user IDs in a text
'box after you click a button. Make sure the program verifies that none Of the IDs are identical.
'Each userid should include a mixture Of alphabetic characters And numbers.
Private Sub btnGenerateRandomID_Click(sender As Object, e As EventArgs) Handles btnGenerateRandomID.Click
Dim strChar As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
Dim rand As New Random
Dim strID As String = ""
For count_ids As Integer = 0 To 999
For count_chars As Integer = 0 To 7
strID += strChar(rand.Next(0, 62))
Next count_chars
lblRandomId.Text = strID
Next
End Sub
End Class
Here is the actual question "Q. Write a program to display 1000 8-character random user IDs in a text box after you click a button. Make sure the program verifies that none of the IDs are identical. Each userid should include a mixture of alphabetic characters and numbers.
Explain your program in your essay, with screenshots. Include a paragraph on the random number generator used in Visual Basic, and answer the question: how should the random number generator be best seeded?"
First of all, Welcome to StackOverflow,
From what i understand from your post you want to generate 1000 8 Character long Unique ID's
First of all we declare our variables
Dim Characters As String = "AZERTYUIOPQSDFGHJKLMWXCVBN0123456789" 'Declare All Characters on one string
Dim IDsList As New List(Of String) With {.Capacity = 1000} 'You can limit the capacity to 1000
Dim Id As String = ""
Dim Rand As New Random
Now we begin to genearte ID's and add them to IDsList using a nested loop
For i As Integer = 0 To 999 'This is a Zero Based Index so 999 is actually 1000
For _i As Integer = 0 To 7 'This also means 7 is 8
Id += Characters(Rand.Next(0, 36))
Next
IDsList.Add(Id)
Id = ""
Next
'You can Check for duplicates by adding this piece of code or use the next one instead
Dim NoDupesIDsList As New List(Of String)
NoDupesIDsList = IDsList.Distinct.ToList
For i As Integer = 0 To 999 'This is a Zero Based Index so 999 is actually 1000
For _i As Integer = 0 To 7 'This also means 7 is 8
Id += Characters(Rand.Next(0, 36))
Next
If not IDsList.contains(Id) then
IDsList.Add(Id)
End if
Id = ""
Next
Use a Textbox with multiline and scroll bar for better experience
Feel free to ask me anything via comments
PS: I tested my method and it's working , enjoy it !
This function will return the ASCII characters between 48 an 122. That will include some characters that are not letters or numbers but this makes the ids even more unique and simplifies the code.
The For loop builds the ids with a length of 8. Then the id is checked for uniqueness with the .Contains method. Only if it is not in the list, it is added to the list and the counter is incremented.
Private Rnd As New Random
Private Function GetListOfIDs() As List(Of String)
Dim Counter As Integer
Dim lst As New List(Of String)
Dim id As String = ""
Do While Counter < 1000
id = ""
For i = 0 To 7
id &= Chr(Rnd.Next(48, 123))
Next
If Not lst.Contains(id) Then
lst.Add(id)
Counter += 1
End If
Loop
Return lst
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim lst = GetListOfIDs()
TextBox1.Text = String.Join(vbCrLf, lst)
End Sub
EDIT
As per suggestion by Caius Jard in comments I have added a solution using a HashSet. Same idea only a HashSet will not accept duplicate entries. The .Add method returns a boolean telling you if the Add was successful.
Private Function GetListOfIDs() As HashSet(Of String)
Dim hs As New HashSet(Of String)
Dim id As String = ""
Do While hs.Count < 1001
id = ""
For i = 0 To 7
id &= Chr(Rnd.Next(48, 123))
Next
If hs.Add(id) Then
Counter += 1
End If
Loop
Return hs
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim hs = BuildHashSet()
TextBox1.Text = String.Join(vbCrLf, hs)
End Sub
This method is probably more efficient because a HashSet is designed for hight performance. For 1000 items I did not notice any difference in the user interface. The text box updated immediately with both methods.
This will create the names:
Function RandomName(length As Integer) As String
Shared rnd As New Random()
Shared corpus() As Char = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray()
Return New String(Enumerable.Range(0, length).Select(Function(c) corpus(rnd.Next(corpus.Length))).ToArray())
End Function
Iterator Function GetUniqueNames(length As Integer, count As Integer) As IEnumerable(Of String)
Dim names As New HashSet(Of String)
For i As Integer = 0 To count
Dim name As String = RandomName(length)
While names.Contains(name)
'Potential (but unlikely) halting problem
name = RandomName(length)
End While
names.Add(name)
Yield name
Next
End Function
Dim uniqueNames = GetUniqueNames(8, 1000)
But do you really want to display 1000 of them in a single label?
lblRandomId.Text = string.Join(vbCrLf, uniqueNames)
Let's talk about your code.
Dim strChar As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
This assignment will work in your loop because a String is really an array of Char. This is why you can refer to an index in the string.
Dim rand As New Random()
The .net Random class provides a seed for Random based on system time. Only rarely would you want to provide a seed.
From the docs https://learn.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1
CONSTRUCTORS
Random() Initializes a new instance of the Random class
using a default seed value.
Random(Int32) Initializes a new instance of the Random class, using
the specified seed value.
For count_ids As Integer = 0 To 999
A For loop is not appropriate for this problem. We only want to increment the counter if we get a unique ID. The above For loop will increment on every iteration.
Do While Counter < 1000
'Code here
Loop
Notice in my code the counter is only incremented if the ID is unique.
The following loop should work fine but above this code we need to reset strID to an empty string. Otherwise we will have a very long string.
For count_chars As Integer = 0 To 7
strID += strChar(rand.Next(0, 62))
Next count_chars
You should not update the user interface (the label) on each iteration of the loop. Repainting the screen is one of the slowest operations in code. This line will overwrite the string in the label on every iteration.
lblRandomId.Text = strID
Move the update of the UI to after both loops are complete
Your code never checks for duplicates.
Now let's fix it.
We use a List(Of T) to accumulate the IDs. The T stands for Type; in our case it is String. A List is like an array only you don't have to know ahead of time how many entries there will be. No ReDim Preserve required.
Moved Dim strID As String = "" to the beginning of the inner loop so we will get a new strID on each iteration of the outer loop.
Changed strID &= strChar(rand.Next(0, 62)). &= instead of +=. In VB.net we use the ampersand to concatenate strings although the plus sign will work. The .Next method of the Random class has an overload that takes 2 Integers. It is inclusive of the first and exclusive of the second which means (0, 62) will return numbers form 0 to 61. Your string with a length of 62 has indexes of 0 to 61.
Next we check for duplicates with the .Contains method of the List class. This method does just what you would expect. We pass the new ID to the method and it returns a Boolean telling if the string is already in the list.
If it is not in the list, we add it to the list and increment the counter. The counter is only incremented if we have a successful add.
Finally we update the user interface by using a method of the String class. the .Join method takes a separator and the list to join. The TextBox must be multiline and have scroll bars.
I changed the names of the controls so I could test it in my testing program.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim lst As New List(Of String)
Dim strChar As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
Dim rand As New Random()
Dim counter As Integer
Do While counter < 1000
Dim strID As String = ""
For count_chars = 0 To 7
strID &= strChar(rand.Next(0, 62))
Next
If Not lst.Contains(strID) Then
lst.Add(strID)
counter += 1
End If
Loop
TextBox1.Text = String.Join(vbCrLf, lst)
End Sub
EDIT
The official documentation for this method can be found here.
https://learn.microsoft.com/en-us/dotnet/api/system.string.join?view=netcore-3.1
I know it will be difficult to read but just take a look. Eventually you will be able to understand it and will be using these docs a lot.
String.Join(separator, List(Of String))
The separator is what to put between the strings in the list. In our case that is vbCrLf which is a vb constant for new line. Cr = Carraiage Return and Lf = Line Feed. Other types of collections that contain strings can also use this method.
The method takes each string in the list and adds the separator. After it is done with the list it returns one long string which we display in the TextBox.

Showing Multiple Numbers from RNG

What I am trying to do is create an RNG button that will generate 5 unique numbers between 1-99. This is what I have so far:
Private Sub GenerateButton_Click(sender As Object, e As EventArgs) Handles GenerateButton.Click
Dim rand As New Random()
Dim rememberset As New HashSet(Of Integer)
Dim value As Integer
While rememberset.Count < 6
value = rand.Next(1, 99)
If rememberset.Add(value) Then
LotteryLabel.Text = value.ToString()
End If
End While
End Sub
Every time I click the generate button, I just get 1 number. I'm trying to get 5 to display in this format (1, 2, 3, 4, 5). Any ideas? Thanks.
Your LotteryLabel.Text is always set to the string of only one number ( I guess you will see only the last number)
You need to append the value: Easy (but maybe slow) solution should be
LotteryLabel.Text = LotteryLabel.Text & ", " & value.ToString()

Declaring a one dimensional array of 6 and showing a random value between 1-6 in a textbox

I need help with my program. I declared a one-dimensional array of 6 and I want to show random values between 1-6 in a text box
My question is how do I show values in my array in textbox1.text?
Here is my code:
Public Sub ClickMyFirstClassButton()
If FirstClass.Checked = True Then
'This piece of code declares an array
Dim Seats As Integer()
'This is a One Dimensional Array
ReDim Seats(6)
TextBox1.Text = (String.Format("First Class is checked. The number of seats are : ", (Seats)))
'ElseIf FirstClass.AutoCheck = True Then
'MessageBox.Show("FirstClass is Auto checked")
End If
End Sub
I messed around with my program and this is what I did.
Public Sub ClickMyFirstClassButton()
If FirstClass.Checked = True Then
'Dim Seats As Integer() = {1, 2, 3, 4, 5, 6}
Dim Seats(0 To 6) As Integer
Seats(0) = 1
Seats(1) = 2
Seats(2) = 3
Seats(3) = 4
Seats(4) = 5
Seats(5) = 6
TextBox1.Text = (String.Format("First Class is checked. Your seat is : {0}", Seats(RandomNumber(Seats))))
MessageBox.Show(String.Format("First Class is checked. Your seat is : {0}", Seats(RandomNumber(Seats))))
'ElseIf FirstClass.AutoCheck Then
'MessageBox.Show("FirstClass is Auto checked")
End If
End Sub
Where you currently have "(Seats)", replace it with string.join(", ", Seats) and see if you like those results.
(Though I admit I'm not sure what this has to do with random values, it should display the values in your array.)
I am still unsure as to why you are using an array in this way If you just want a number between 1 and 6, this will do what you want:
Public Sub ClickMyFirstClassButton()
If FirstClass.Checked = True Then
TextBox1.Text = (String.Format("First Class is checked. The number of seats are : " & CInt(Math.Ceiling(Rnd() * 6)) + 1))
End If
End Sub
Is this a learning exercise? If so I would be keen to see the question that has been asked of you as it doesn't make much sense to me currently.

Sorting using an index number

How do i implement a index based sort in vb.net
Could someone guide me. By giving me a head start
eg
array = 9 8 7 6 5 4 3 2 1
Index Number = 5
Counting from 9 and the 5th character is 5.
So the first sorted character is 5.
Remove 5 and remains 9 8 7 6 4 3 2 1
start value should be from 4(current 5th character) now 5th character is 9 since it's circular
unsorted array : 8 7 6 4 3 2 1
sorted array : 5 9
any hints
First off, I definitely wouldn't call this "sorting"; it's a bit more like deterministically (non-randomly) "shuffling" the array. But I'll take a stab at this…
Basically, start by using List(Of T) rather than arrays, because they allow you to easily and remove at any point in the list, rather than arrays which are a fixed size. Next, use a running counter to track your current position in the input list, and use the Mod operator to make the index effectively 'wrap' around the end of the list. Use a While loop to continue until all the items from the input have been processed. It should look something like this:
Dim input As New List(Of Integer) From { 9, 8, 7, 6, 5, 4, 3, 2, 1 }
Dim stepBy As Integer = 5
Dim index As Integer = 0
Dim output As New List(Of Integer)
While input.Count > 0
index = (index + stepBy - 1) Mod input.Count
output.Add(input(index))
input.RemoveAt(index)
End While
In this case the output is:
5, 9, 3, 6, 7, 4, 1, 8, 2
I thought this was an interesting question and I loved the answer by p.s.w.g....
...but I was curious to see if any of the built-in .Net collections would facilitate a fairly trivial circular list.
This is what I came up with using the LinkedList class:
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim originalIntegers() As Integer = {9, 8, 7, 6, 5, 4, 3, 2, 1}
Dim output As New List(Of Integer)
Dim circleInts As New CircularIntegerList(originalIntegers)
circleInts.MoveForward(4) ' move forward 4 from the 1st to get the 5th slot
While circleInts.Count > 0
If circleInts.Current.HasValue Then
output.Add(circleInts.Current)
End If
circleInts.RemoveCurrent() ' next number in sequence becomes the current one
circleInts.MoveForward(4) ' move forward another 4, net jump is 5 from the deleted one
End While
Dim result As String = String.Join(",", output.Select(Function(x) x.ToString).ToArray)
Debug.Print(result)
End Sub
End Class
Public Class CircularIntegerList
Private values As New LinkedList(Of Integer)
Private _current As LinkedListNode(Of Integer)
Public Sub New(ByVal data() As Integer)
If data.Length > 0 Then
values = New LinkedList(Of Integer)(data)
_current = values.First
End If
End Sub
Public ReadOnly Property Current As Integer?
Get
If Not IsNothing(_current) Then
Return _current.Value
Else
Return Nothing
End If
End Get
End Property
Public ReadOnly Property Count As Integer
Get
Return values.Count
End Get
End Property
Public Sub RemoveCurrent()
If Not IsNothing(_current) Then
Dim tmp As LinkedListNode(Of Integer) = If(IsNothing(_current.Next), values.First, _current.Next)
values.Remove(_current)
If values.Count > 0 Then
_current = tmp
Else
_current = Nothing
End If
End If
End Sub
Public Sub MoveForward(Optional ByVal NumberOfJumps As Integer = 1)
If Not IsNothing(_current) Then
For i As Integer = 1 To NumberOfJumps
_current = If(IsNothing(_current.Next), values.First, _current.Next)
Next
End If
End Sub
End Class

Visual Basic - Looping an array 100 times not working?

I'm trying to loop this array 100 times (gets a number from 0-99,999). I've tried it several different ways with no luck. I've got it set up so you click a button and it generates the array. The user will then enter a number and hit the other button to check how many times that number shows up in the group of a 100 numbers. Any thoughts how to fix it? I'm stuck.
Dim i As Integer
Dim rnd As New Random()
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEnter.Click
Dim num As Integer
If Int32.TryParse(txtEnter.Text, num) AndAlso num >= 0 AndAlso num < 10 Then
lblNumber.Text = i.ToString()
Dim counts = From c In i.ToString()
Group By c Into Group
Select DigitGroup = New With {.Count = Group.Count(), .Digit = c, .Group = Group}
Order By DigitGroup.Count Descending, DigitGroup.Digit
Dim numCount = counts.FirstOrDefault(Function(grp) grp.Digit.ToString() = num.ToString())
If numCount IsNot Nothing Then
Dim numMessage = String.Format("There are {0} number {1}'s found.", numCount.Count, num)
MessageBox.Show(numMessage)
Else
MessageBox.Show("Your number does not contain a " & num)
End If
Else
MessageBox.Show("Please enter a number between 0 and 9.")
End If
End Sub
Private Sub btnGetNumber_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGetNumber.Click
btnEnter.Enabled = True
i = 0
Do Until i > 100
Dim randomInt = rnd.Next(0, 100000)
i = i + 1
i = rnd.Next(0, 100000)
Loop
End Sub
End Class
First of all, it is common to use For Loops when you know the number of loops.
Secondly, you forgot to increment i in the until loop
Finally, you don't need to redeclare rnd in every loop. Something like that sounds better to me :
Dim rnd As New Random()
For i = 1 To 100
Dim randomInt = rnd.Next( 0 , 100000 )
Next
Move the New Random() out of that loop. Make it global and create the instance just one time.
(The Random generator starts using a seed obtained from the current time. Declaring a Random variable inside a loop result in the same seed used again and again. This gives back the same number defeating the randomness of the function) It is like: http://xkcd.com/221/
See another explanation here
Of course, if you don't increment the variable i used to control the loop, you will loop forever
Dim i As Integer
Dim rnd As New Random()
.....
i = 0
Do Until i > 100
Dim randomInt = rnd.Next(0, 100000)
i = i + 1
Loop
Said that, now I can't get what are you trying to do here. There is no array to check and you do not use the value obtained from the Random generator, simply, your i variable exits with value 101.
Now I am just guessing what are your intentions, but perhaps you want just this?
i = rnd.Next(0, 100000)
This will give to the variable i a random number and your subsequent code checks how many, of the required digit, are present in i
I see that you are not adding the variable "i" to increment:
i = 1
Do Until i > 100
Dim rnd As New Random()
Dim randomInt = rnd.Next(0, 100000)
i+=1 'Increment value of i by 1, same as i = i + 1
Loop
The variable of "i" will always be 1 if not incremented. Check that and let me know if that solves the problem!