-2

I have this so far but it just outputs 0

Option Explicit On
Option Strict On
Option Infer Off

Public Class frmMain
    Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
        Me.Close()
    End Sub

    Private Sub btnCalc_Click(sender As Object, e As EventArgs) Handles btnCalc.Click
        Dim inFile As IO.StreamReader
        Dim intBill As Integer
        Dim avg As Integer
        Dim trueAvg As Integer

        If IO.File.Exists("monthlyBills.txt") Then
            inFile = IO.File.OpenText("monthlyBills.txt")
            Do Until inFile.Peek = -1
                Integer.TryParse(inFile.ReadLine, intBill)
                avg += intBill
            Loop
            inFile.Close()
            trueAvg = CInt(avg / 12D)
            lblAvg.Text = trueAvg.ToString()
        Else
            MessageBox.Show("Cannot find the file.", "monthlyBills",
                            MessageBoxButtons.OK, MessageBoxIcon.Information)
            lblAvg.Text = "N/A"
        End If
    End Sub
End Class

Here is the "monthlyBills.txt" text file:

141.71
156.75
179.25
141.71
130.19
115.05
95.65
86.78
85.45
79.99
98.45
126.78
  • As suggested in the answer, `TryParse` returns a `Boolean` to indicate whether the parsing was successful or not. None of your values are integers so the parsing always fails. When `TryParse` returns `False`, the output parameter is set to zero. That would explain why you get zero as a result. This is all in the documentation and you could have seen it all happening in the debugger. If you haven't read the relevant documentation or debugged your code then it's too soon to be posting here. SO is for issues that you've tried to solve and can't. Reading and debugging is part of the trying. – jmcilhinney Nov 21 '19 at 00:21

2 Answers2

1

The problem is that none of the values in your text file is an integer and yet, you're trying to parse them as integers. You should use a Decimal type instead.

One more thing, whenever you use a .TryParse() method, you probably want to check its return value to make sure whether or not the parsing was successful. An If statement would help in this case.

This should work fine:

Dim inFile As IO.StreamReader
Dim intBill As Decimal
Dim avg As Decimal
Dim trueAvg As Integer

If IO.File.Exists(filePath) Then
    inFile = IO.File.OpenText(filePath)
    Do Until inFile.Peek = -1
        If Decimal.TryParse(inFile.ReadLine, intBill) Then
            avg += intBill
        Else
            ' TODO: decide what you should do if a line isn't a decimal value.
        End If
    Loop
    inFile.Close()
    trueAvg = CInt(avg / 12D)
    lblAvg.Text = trueAvg.ToString()
Else
    MessageBox.Show("Cannot find the file.", "monthlyBills",
                    MessageBoxButtons.OK, MessageBoxIcon.Information)
    lblAvg.Text = "N/A"
End If

Notes:

  • I changed the type of both inBill and avg to Decimal but kept trueAvg as in integer just in case you need that end value to be rounded. If you don't have a specific reason for that, you should use a Decimal instead and get rid of the CInt.

  • Floating numbers in .NET can be represented in two different categories of types; a binary representation (like Single or Double types), and a decimal representation (the Decimal type). For your particular situation, I suggested using Decimal because you seem to be dealing with prices and Decimal would be more suitable. You may read more about the difference in this post.

  • 1
    (btw, congrats :) 2 small notes (to the OP). `avg` is not representing an average but a sum. So, the name is misleading. `12D` shouldn't be *hard-coded*, it should represent the count of the elements read from the file and actually parsed. – Jimi Nov 21 '19 at 00:08
1

To use a method that doesn't have a .TryParse you must be very sure that each line in the text file is a number.

.ReadAllLines returns an array where each element is a line in the text file.

Next we use a bit of Linq to change each line (which is a string) to a Decimal value. The .Trim removes any white space that may be there. Don't worry about the IEnumerable. That is what this Linq returns. It just means you can loop through it with a For Each loop.

Then we can just call the .Average method on the IEnumerable and we are done.

Private Sub btnCalc_Click(sender As Object, e As EventArgs) Handles btnCalc.Click
    Dim lines As String() = File.ReadAllLines("monthlyBills.txt")
    Dim decs As IEnumerable(Of Decimal) = From line In lines
                                          Select CDec(line.Trim)
    Dim avg As Decimal = decs.Average
    lblAvg.Text = avg.ToString("N2")
End Sub

Here is another example that does not use the Linq query and does use .TryParse. If you use a List instead of an array you don't have to know how many items are going to be added in advance. Also you don't need to keep track of the index. You still use the .Average method on the list.

Private Sub btnCalc_Click(sender As Object, e As EventArgs) Handles btnCalc.Click
    Dim lines As String() = File.ReadAllLines("monthlyBills.txt")
    Dim decs As New List(Of Decimal)
    Dim dec As Decimal

    For Each line As String In lines
        If Decimal.TryParse(line, dec) Then
            decs.Add(dec)
        Else
            MessageBox.Show(line & " is not a number and is being excluded from calculations.")
        End If
    Next

    Dim avg As Decimal = decs.Average
    lblAvg.Text = avg.ToString("N2")
End Sub
Mary
  • 14,926
  • 3
  • 18
  • 27
  • 1
    In the first snippet, the average can be just `dim avg As Decimal = Decimal.Round(lines.Average(Function(s) CDec(s)), 2)` – Jimi Nov 21 '19 at 01:06
  • 1
    @Jimi Thanks for the one-liner! I am still a bit shaky on those Function(s) things. – Mary Nov 21 '19 at 01:13