Bubble sort Array program, Selecting a certain number - vb.net

I'm trying to find a number out of a random set of X amount of numbers. I don't want you to put it in yourself I would just like suggestions so I can learn.
What my code does it allows me to display any amount of random numbers I would like. I can't search within those numbers and that's where I'm lost.
CODE DISPLAYS NO ERRORS. "Stepping into" is still new to me.
Private Sub GenerateAndSearch(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSort.Click, btnGenerate.Click
Static intDataArray(-1) As Integer
Dim btnButtonClicked As Button = sender
Select Case btnButtonClicked.Tag
Case "Generate Array"
Call GenerateSortedArray(intDataArray)
Me.lstbox1.Items.Clear()
Call DisplayData(intDataArray, Me.lstbox1, "Sorted array:")
Case "Search Array"
Dim intNumToFind As Integer = Val(Me.txtNumElements.Text)
Dim intNumFoundIndex As Integer
intNumFoundIndex = BinarySearch(intDataArray, intNumToFind)
If intNumFoundIndex = -1 Then
Me.Label1.Text = "Number not found."
Else
Me.Label1.Text = "Number found at index" & intNumFoundIndex
End If
End Select
End Sub

Related

Calculate cost of several items with tax and a discount

Can anyone help with this school task I have
The task is to ask the user for items and the cost of the items until they chose to stop. Then combine all the costs and take 20% VAT and 10% off from 2 randomly selected items.
Here is the code I have so far (I have 2 buttons and a listbox)
Public Class Form1
Dim CurrentA As Integer
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim Items(CurrentA) As String
Dim Coins(CurrentA) As Single
Dim Stay As String
CurrentA = 0
Do Until CurrentA = 20
Items(CurrentA) = InputBox("Please Enter The Item")
Coins(CurrentA) = InputBox("Please Enter The Cost Of The Item")
Stay = InputBox("Type Yes If More Items or Type No if no More")
Stay = Stay.ToLower
If Stay = "yes" Then
End If
If Stay = "no" Then
Exit Do
End If
ListBox1.Items.Add(Items(CurrentA) & " " & Coins(CurrentA))
CurrentA += 1
Loop
End Sub
End Class
First, a few comments on the code you presented.
Dim CurrentA As Integer
'An Integers default value is zero, I don't see why this is a class level variable
'always declare variables with as narrow a scope as possible
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Dim Items(CurrentA) As String 'Declares an Array of Type String with an Upper Bound of 0
'Upper Bound is the highest index in the array
'Arrays start with index 0
'So your array will have 1 element at index 0
Dim Coins(CurrentA) As Single
Dim Stay As String
CurrentA = 0 'unnecessary because the default of CurrentA is already 0, but OK for clarity because it could have been changed elsewhere
'This is behaving like a console application with the code repeating in a loop.
'In Windows Forms it would be more likely to do this in a button click event (btnAddItem)
Do Until CurrentA = 20
'On the first iteration CurrentA = 0
'On the second iteration CurrentA = 1 - this exceeds the size of your array
'and will cause an index out of range error
Items(CurrentA) = InputBox("Please Enter The Item")
'With Option Strict on you must change the input to a Single
Coins(CurrentA) = CSng(InputBox("Please Enter The Cost Of The Item"))
Stay = InputBox("Type Yes If More Items or Type No if no More")
Stay = Stay.ToLower 'Good! The user might no follow directions exactly
If Stay = "yes" Then
'This is kind of silly because it does nothing
End If
'Lets say I say no on the first iteration
'This avoids the index out of range error but
'nothing is added to the list because you Exit the loop
'before adding the item to the ListBox
If Stay = "no" Then
Exit Do
End If
ListBox2.Items.Add(Items(CurrentA) & " " & Coins(CurrentA))
CurrentA += 1
Loop
End Sub
We could use arrays but not knowing how many items will be added means either making the array bigger than needed or using Redim Preserve on every addition. A much better choice is a List(Of T). They work a bit like arrays but we can just add items without the ReDim stuff.
Private lstCost As New List(Of Single)
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
'Pretend this button is called btnAdd, and you have 2 test boxes
lstCost.Add(CSng(TextBox2.Text))
'The $ introduces an interpolated string. It is a step up form String.Format
ListBox2.Items.Add($"{TextBox1.Text} - {CSng(TextBox2.Text):C}") 'The C stands for currency
TextBox1.Clear()
TextBox2.Clear()
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
'Pretend this button is called btnTotal
'Dim total As Single = (From cost In lstCost
' Select cost).Sum
Dim total As Single = lstCost.Sum
Label1.Text = total.ToString("C") 'C for Currency
End Sub

Using a Sub Procedure to call a random number and display a string to a label

Im trying to get a random number to generate and take said random number to display a certain line of text assigned to that number to a label through a Sub Procedure.
If this is any easier:
Generate Random Number 1 Through 5
Call Random Number using Sub Procedure
Display a string to a label that is connected to that random number.
I'll show my code just so you guys know what my direction is and if it's correct.
Public Class Form1
Private Sub btnInsult_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnInsult.Click
Dim strInsult As String
Dim intNumber As Integer
Randomize()
intNumber = Int((5 - 1 + 1) * Rnd() + 1)
End Sub
Sub showInsult()
End Sub
End Class
It really isn't much and I think I'm moving in the right direction. Please ask me if you need more clarification on things.
I had a similar piece of code for generating random messages.
Unlike your code above, this was written inside a form module, not a class one and prints to a text box, not a label. I am not sure whether by
Display a string to a label
you actually mean changing an actual label caption. If so, then use the showInsultEx sub instead. Here it is, adapted to your needs. I hope this helps.
Private arrInsults() As Variant
Private nInsultCount As Integer
Private Sub Insult_InitRepertoire()
'init the insult array
arrInsults = Array( _
"Insult 1", _
"Insult 2", _
"Insult 3", _
"Insult 4", _
"Insult 5")
nInsultCount = UBound(arrInsults) - LBound(arrInsults) + 1
End Sub
Private Sub showInsult()
'init the insult array if empty
If nInsultCount = 0 Then Insult_InitRepertoire
'get a random entry from the insult table
'and print it in the text field
Randomize
Me.TextBox1.Text = arrInsults(LBound(arrInsults) + Int(Rnd() * nInsultCount))
End Sub
Private Sub btnInsult_Click()
'invoke the pseudo-random inslut generator
showInsult
End Sub
Private Sub UserForm_Initialize()
'prevent user input
Me.TextBox1.Locked = True
End Sub
Private Sub showInsultEx()
Dim nId As Integer
'init the insult array if empty
If nInsultCount = 0 Then Insult_InitRepertoire
'get a random entry from the insult table
'and print it in the text field
Randomize
nId = LBound(arrInsults) + Int(Rnd() * nInsultCount)
'get a control associated with the insult number
'change its caption to the generated text
'you'll have to make sure to number the controls
'according to the array indices
Me.Controls("Label" & nId).Caption = arrInsults(nId)
End Sub

Can't reconcile votes with candidates

Good morning all,
I'm working on a voting program in Visual Basic (using Visual Studio 2013 if that makes any difference), and I can't seem to get the votes per candidate to function.
This is an assignment so I must use the listbox.DoubleClick event handler for the selected index to tally the votes.
Thus far I have written the entire program to my liking but I cannot get the votes to coincide with the candidates. I think it has to do with this block of code
Try
'Selected candidate gets a vote tallied
vote(candidateList.SelectedIndex) += 1
candidateList.SelectedIndex = -1
Catch exc As IndexOutOfRangeException
MessageBox.Show("Please click on a candidate to vote.", "Attention!")
End Try
My entire project can be seen here if needed - Voting Machine source code
Any idea what will help my program reconcile the data? Or what my error is?
Thank you!
Edit- I've gotten it mostly working now, I get an accurate number of votes per candidate, but now I need to figure out how to get both the candidate name and their total votes in the same listbox.
The above code displays the correct votes in the correct order, but if I try to add the candidateList.selectedItem into the mix it throws an invalid cast exception as the string (candidates name) cannot be converted to an integer. How do I get the selectedItem and increment the count for the selected index? I'm stuck at this point now for most of today and help would be greatly appreciated.
Thank you!
I took a look at your code. You need to initialize the "vote" array before you start using it. You have this line:
Dim vote() As Integer
Which doesn't actually initializes the array of integers. Here are some examples how you could initialize is with a length of 3 or 3 variables.
Dim vote(3) As Integer
Dim vote As Integer() = {1,2,3}
By the way, it would also be best to check that "candidateList.SelectedIndex" has an actual valid value (isn't -1).
In your code, the vote array is declared but not initialized which is causing the NullReferenceException
Please initialize the array with proper dimension, For instance you can do that in your code in "showCandidates()" function as follows,
Sub showCandidates()
'Display the candidates in the listbox and sort alphabetically by last name
Dim query = From candidate In Candidates
Let firstName = candidate.Split(" "c)(0)
Let lastName = candidate.Split(" "c)(1)
Let name = firstName & " " & lastName
Order By lastName
Select name
For Each Name As String In query
candidateList.Items.Add(Name)
Next
'Initialize the vote array.
ReDim Preserve vote(candidateList.Items.Count)
End Sub
ReDim the vote array whenever you are adding a candidate to the list box (i-e nominate candidate) otherwise you may get an IndexOutOfBounds Exception.
I figured out the solution to my problem. Many thanks to those that helped me!
Imports System.IO
Public Class Voting
Dim Candidates() As String
Dim votes() As Integer
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Get default values and views for Voting Machine
resultsList.Visible = False
candidateList.Location = New Point(143, 71)
tallyVotes.Enabled = False
resultsList.Enabled = False
Label1.Text = "Click 'Nominate Candidate' to enter a candidate, or 'Start Voting'" & vbCrLf & "to end nominations and start the voting."
End Sub
Private Sub candidateList_SelectedIndexChanged(sender As Object, e As EventArgs) Handles candidateList.SelectedIndexChanged
End Sub
Private Sub resultsList_SelectedIndexChanged(sender As Object, e As EventArgs) Handles resultsList.SelectedIndexChanged
End Sub
Private Sub nominateCandidate_Click(sender As Object, e As EventArgs) Handles nominateCandidate.Click
'Instructions
MessageBox.Show("When finished entering candidates, simply press enter on a blank line.", "Instructions")
'Gather list of Candidates
Dim candidateName = InputBox("Enter the name of your candidate (first and last name please):", "Candidate Name", "", 500, 500)
Dim i As Integer = 0
'Loops until a null string is entered signaling the end of input
Do Until String.IsNullOrEmpty(candidateName)
ReDim Preserve Candidates(i)
Candidates(i) = candidateName
i += 1
candidateName = InputBox("Enter the name of your candidate (first and last name please):", "Candidate Name", "", 500, 500)
Loop
End Sub
Private Sub startVoting_Click(sender As Object, e As EventArgs) Handles startVoting.Click
'Disable the Nomination button
nominateCandidate.Enabled = False
'Enable the tally votes button
tallyVotes.Enabled = True
'Set the label text to give instructions for tallying votes.
Label1.Text = "Vote for a candidate by double-clicking his or her name." & vbCrLf & "End the voting by clicking on 'Tally Votes'."
'Call sub to display the candidates for voting
showCandidates()
End Sub
Private Sub tallyVotes_Click(sender As Object, e As EventArgs) Handles tallyVotes.Click
'Makes results listbox visible and moves the candidate list to the left
resultsList.Visible = True
candidateList.Location = New Point(14, 71)
'Call the sub to tally the votes and display the winner
getResults()
End Sub
Private Sub candidateList_DoubleClick(sender As Object, e As EventArgs) Handles candidateList.DoubleClick
'Selected candidate gets a vote tallied
Try
'Selected candidate gets a vote tallied
votes(candidateList.SelectedIndex) += 1
candidateList.SelectedIndex = -1
Catch exc As IndexOutOfRangeException
MessageBox.Show("Please click on a candidate to vote.", "Attention!")
End Try
End Sub
Sub showCandidates()
'Display the candidates in the listbox and sort alphabetically by last name
Dim query = From candidate In Candidates
Let firstName = candidate.Split(" "c)(0)
Let lastName = candidate.Split(" "c)(1)
Let name = firstName & " " & lastName
Order By lastName
Select name
For Each Name As String In query
candidateList.Items.Add(Name)
Next
ReDim Preserve votes(candidateList.Items.Count - 1)
End Sub
Sub getResults()
'Add the results to the Results Listbox
For Each i In votes
resultsList.Items.Add(i)
Next
'Declare Winner
Dim mostVotes As Integer = 0
For Each item In resultsList.Items
If item > mostVotes Then
mostVotes = item
End If
Next
resultsList.SelectedItem = mostVotes
candidateList.SelectedIndex = resultsList.SelectedIndex
Dim winner = candidateList.SelectedItem
MessageBox.Show("The winner is " & winner)
End Sub
End Class

How do I add string to an array x2 and the get it back?

Essentially what I am trying to do is write a program where you input the person's name and their date of birth, store them to an array (note sure if I have to do two separate arrays) and then by entering their name into another text box and clicking another button I can get the date of birth back.
I know I have to include an if-loop, I know how to declare an array.
I am guessing that I maybe need to use a select case.
Here is the code:
Public Class Form1
Dim Name(5) As String
Dim DOB(5) As String
Dim i As Integer
Private Sub btnNameEnter_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnNameEnter.Click
Name(i) = txtInputName.Text
DOB(i) = txtInputDOB.Text
If i = 6 Then
MsgBox("You cannot enter any more names.")
End If
For i = 1 To 5
Name(i) = i
txtInputName.Clear()
txtInputDOB.Clear()
Next i
End Sub
Private Sub btnFindDOB_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFindDOB.Click
Select Case Name(i)
Case Is Name(1)
MsgBox("Date of birth: " & DOB(1))
Case is Name(2)
MsgBox("Date of birth: " & DOB(2))
Case is Name(3)
MsgBox("Date of birth: " & DOB(3))
Case is Name(4)
MsgBox("Date of birth: " & DOB(4))
Case is Name(5)
MsgBox("Date of birth: " & DOB(5))
End Select
End Sub
End Class
I would show a picture of the program but visual basic keeps deleting it for some reason and doesn't let me re add the buttons.
Here is an image of the error list:
http://gyazo.com/2489a307f4a8e2d9ce65aa2ad79b04f1 )
Public Class Form1
Dim DOB(5) As String
Dim i As Integer
Private Sub btnEnter_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEnter.Click
Dim Name(5) As String
Dim Counter As Integer
txtNameInp.Text = Name(i)
txtDOBInput.Text = DOB(i)
Counter = 0
For i = 1 To 5
If Counter = 6 Then
MsgBox("You can only enter 5 names and DOBs")
End If
Name(i) = txtNameInp.Text
DOB(i) = txtDOBInput.Text
Counter = Counter + 1
Next i
End Sub
Private Sub btnFindDOB_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFindDOB.Click
Select Case Name(i)
Case Name(1)
MsgBox(DOB(1))
Case Name(2)
MsgBox(DOB(2))
Case Name(3)
MsgBox(DOB(3))
Case Name(4)
MsgBox(DOB(4))
Case Name(5)
MsgBox(DOB(5))
End Select
End Sub
End Class
Here's an error: http://gyazo.com/487290c3e523003fe58f82a15fdf6faa - this one occurs when I try and enter the second number
It is hard to be to precise using a picture of the errors instead of comments in the code indicating the location and text of the error, but from what I can see:
Forms already have a Name property and you are trying to redefine it via your array. use something like myNames instead.
You have a module level variable named i and a local one as well. Change the global one to something useful like curPosition. This will track with element you are currently storing to.
If you want to stop adding to the array at 6 you need to do so in code. Add Exit Sub after the MsgBox; you want to do this before you store anything to the arrays, not after. Maybe add a message saying - 'now I will tell you the DOB for a name`.
If you want to be clever (doubtful) have both a 'Guess Name' and Guess DOB button on the form and report the Name for a given DOB. Its basically the same code.
the button enter code will run every time they click so you do not need a loop. This is plain nonsense by the way: Name(i) = i you are overwriting everything with whatever i happens to be. Just add to myNames and myDOB using curPosition as the index and then increment it:
myNames(curPosition) = txtInputName.Text
The relational error is from this: Case Is Name(1)
The error is telling you that it expects a relational operator, which Is is not (Is is used with Objects, which a string is not). The code is also a bit wonky here because you are not controlling the value if i. To compare txtInputName:
Select Case txtInputName.Text
Case = Name(1) ' ie does txtInputName match the value in Name(1)?
...
- Rather than a case statement, you could use a For Loop here for less code.
Lets learn about classes. Rather than arrays which will dissociate related pieces of info from each other a class will keep the data together.
Public Class Person
Public property Name As String
Public Property DOB As DateTime ' I refuse to store a Date as string
Public Sub New(sName as String, dt as DateTime)
Name = sName
DOB = dt
End Sub
End Class
Next, a nifty list to hold some person objects. A list is like an array but smarter:
Private pList As New List(Of Person)
Add a person:
' ToDo: check that the date is valid using TryParse instead
' this exercise is left to the student
Dim p As New Person(txtInputName.Text, Datetime.Parse(txtInputDOB.Text))
plist.Add(p)
Find a person:
' case insensitive search
Dim search As String = txtNameToFind.Text.ToLowerInvariant
For Each p as Person In pList
If P.Name.TolowerInvariant = search Then
txtDOB.Text = p.DOB.ToString
Exit For
End If
Next
Try this:
Public Class Form1
Dim Name, DOB As List(Of String) 'Lists are better in this situation.
Private Sub btnNameEnter_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnNameEnter.Click
'You don't need to specify the index in lists.
Name.Add(txtInputName.Text)
DOB.Add(txtInputDOB.Text)
txtInputName.Clear()
txtInputDOB.Clear()
End Sub
Private Sub btnFindDOB_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFindDOB.Click
'You get the index of the name you are searching for and get DOB for this index.
MsgBox("Date of birth: " & DOB.Item(Name.IndexOf(txtInputName.Text)))
End Sub
End Class

How can I essentially stop my VB program until a valid value is entered via Text Box?

How can I work around an invalid/null value entered into a text box?
Basically I have a simple program I need to develop to solve a simple quadratic equation:
Public Class Main
Private Sub btnHelp_Click(sender As System.Object, e As System.EventArgs) Handles btnHelp.Click
UserGD.Show()
End Sub
Private Sub btnClear_Click(sender As System.Object, e As System.EventArgs) Handles btnClear.Click
txtStepX.Text = ""
lstResult.Items.Clear()
End Sub
Private Sub cmdGo_Click(sender As System.Object, e As System.EventArgs) Handles cmdGo.Click
Do
txtStepX.Text = InputBox("Please enter a valid value for x!", "Oops!", "")
Loop While String.IsNullOrEmpty(txtStepX.Text)
Dim stepx As Single
Dim X As Single
Dim y As Single
stepx = txtStepX.Text
Dim result As String
For X = -5 To 5 Step stepx
y = (3 * (X) ^ 2) + 4
result = ("x = " & X & " >>>>>>>>>> y = " & y)
lstResult.Items.Add(result)
Next
End Sub
End Class
This is the part I want to focus on:
Do
txtStepX.Text = InputBox("Please enter a valid value for x!", "Oops!", "")
Loop While String.IsNullOrEmpty(txtStepX.Text)
Dim stepx As Single
Dim X As Single
Dim y As Single
stepx = txtStepX.Text
Dim result As String
The above manages to check the text box (after its text value is changed by the Input Box) and loops fine, as long as it is empty... However, say I put a letter in, say, "l", it crashes and Visual Studio gives me the error "Conversion from string 'l' to type 'Single' is not valid." - which is fair enough. Although, I assumed the Null in isNullorEmpty meant it would catch invalid values, such as strings when it's supposed to be single.
I've tried quite a few things, and even my Computing teacher has been trying to get a solution.
I can't remember most of the things I've tried thus far so if I'll give whatever you guys come up with a go just to be on the safe side!
Update
Although not the clearest of code - here is what I found works the best for my needs:
'Written by a very tired and frustrated Conner Whiteside
'With his own blood.
'And sweat.
'And tears.
'Lots of tears.
'28/10/2014
Public Class Main
Private Sub btnHelp_Click(sender As System.Object, e As System.EventArgs) Handles btnHelp.Click
UserGD.Show()
End Sub
Private Sub btnClear_Click(sender As System.Object, e As System.EventArgs) Handles btnClear.Click
txtStepX.Text = ""
lstResult.Items.Clear()
End Sub
' On Go button click
Private Sub cmdGo_Click(sender As System.Object, e As System.EventArgs) Handles cmdGo.Click
'Checks if Text Box value is a number
If IsNumeric(txtStepX.Text) Then
'Declares variables if Text Box value is in fact a number
Dim result As String
Dim stepx As Double
Dim X As Double
Dim y As Double
'Displays error message with a re-input opportunity if previously entered number is out of range.
Do While txtStepX.Text <= 0 Or txtStepX.Text > 10
'InputBox simply changed the value of the TextBox's Text. MUST be an InputBox or there will be nothing to break the loop.
txtStepX.Text = InputBox("The step size for the x values must not be a negative number or above 10." & vbCrLf & "Please enter another number for the step size of the x values.", "Oops!")
'Covers an Empty input given that IsNumeric does not. This can also prevent crashing if the 'Cancel' or 'X' is pressed on InputBox.
If txtStepX.Text = "" Then
'Exits Sub Class in order to avoid running mathematical operations (below) with a string "". Effectively allows a 'reset'.
Exit Sub
End If
Loop
'After all checks, sets Text Boxvalue to variable stepx
stepx = txtStepX.Text
'Loops the solving of the equation from x = -5 to x = 5 with the specified step size.
For X = -5 To 5 Step stepx
'sets the answer of the equation (y) to variable y.
y = (3 * (X) ^ 2) + 4
'concatenates a string in the required format.
result = ("x = " & X & " >>>>>>>>>> y = " & y)
'Adds the result to the List Box before repeating the process for the next value of x.
lstResult.Items.Add(result)
Next
'Catches any non numeric inputs in the Text Box or the Input Box e.g "l".
ElseIf Not IsNumeric(txtStepX.Text) Then
'Displays error message before ending If statement and Sub Class, allowing the user to return to the start and try another input. - No Input Box or Exit Sub needed.
MsgBox("Please enter a valid number for the step size of the values of x.", 64, "Oops!")
End If
End Sub
End Class
Honestly wouldn't have gotten anywhere if it weren't for your efforts!
I would simply check if the input is numeric.
If IsNumeric(txtStepX.text) then
// Your statements
Else
// MsgBox("Please enter a number")
End if
However, it will accept something like 3.5.4
A more complicated solution would be to limit the characters from being entered by checking on each keypress,
Private Sub TextBox1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox1.KeyPress
If e.KeyChar <> ChrW(Keys.Back) Then
If Char.IsNumber(e.KeyChar) Then
//Statements here
Else
e.Handled = True
End If
End If
End Sub
First, I recommend that you use the Double type instead of Single - it won't make any difference to how fast your program runs, but it will reduce rounding errors a lot.
Second, you can use Double.TryParse to check if a string can be parsed as a Double value. IsNumeric has some quirks which you do not want to find out about.
I took the liberty of adjusting the text which is shown to the user, as an "Oops!" before they have even tried to enter a value might be confusing, and it is better to tell them a number is needed than "a valid value":
Dim stepx As Double
Dim inp As String = ""
Dim inputTitle As String = "Number required"
Do
inp = InputBox("Please enter a number for x:", inputTitle)
' change the input box title to indicate something is wrong - if it is shown again.
inputTitle = "Oops!"
Loop While Not Double.TryParse(inp, stepx)
txtStepX.Text = stepx.ToString()