Jump to content

VB Numerical Statistics

Do note that I don't have a problem but rather just sharing code. 

 

Operations I'll share code for includes

  • Largest
  • Smallest
  • Total
  • Mean
  • Median

 

Prerequisite:

  • Create a Windows Form Application in Visual Studio. 
  • Add another Form in the Windows Form Application called ResultForm.vb.

 

The design of my Form1.vb:

Spoiler

1147338175_VisualStudio2019(7).jpg.b27723a6f647d99f697d5b6d6dfeb06b.jpg

  • Consists of only two elements. A button named “CalculateButton” and a textbox named “InputTextBox”
  • For the textbox, “Multiline” is set true and “ScrollBars” is set to Vertical.

 

The design of my ResultForm.vb:

Spoiler

1942223314_VisualStudio2019(8).jpg.b0479fb12b9afb4f0393989153d44906.jpg

  • Consists of three different lables, a textbox under the “Your Input – ” label called “YourInputTextBox”, a textbox under the “Answer – ” label called “OutputTextBox” and a textbox under the “Erorr – ” label called “ErrorTextBox”.
  • All textboxes have “ReadOnly” set true.
  • “YourInputTextBox” and “ErrorTextBox” has “ScrollBars” set to Vertical.

 

Please note that for my code to work, only one numerical statics function will work at one time. 

 

To find lowest number: 

Spoiler

Public Class Form1

    Dim ShowResultForm As Boolean
    Dim LowestNumber As Double = 0
    Dim numberOfLines As Integer = 0
    Dim LinesWithProblem As String = ""
    Dim InputFromUser As String = ""

    Private Sub CalculateButton_Click(sender As Object, e As EventArgs) Handles CalculateButton.Click
        'Code to reset elements
        LowestNumber = 0
        ShowResultForm = False
        LinesWithProblem = ""
        numberOfLines = 0
        InputFromUser = ""

        ResultForm.ErrorTextBox.Text = "no error detected"

        'Function used to handle erroneous input, no input
        If InputTextBox.Text.Trim.Length <= 0 Then
            MessageBox.Show("ERROR : No input. Please input something.", "ERROR")
        Else

            Dim ValidUserInput As New List(Of Double)

            numberOfLines = InputTextBox.Lines.Length
            'For loop to run through every line of the multiline textbox
            For i As Integer = 0 To InputTextBox.Lines.Length - 1
                'Function used to handle erroneous input, only numbers
                'For IsNumeric to work with a multiline textbox, we must check line by line and not the entire textbox
                'Unable to have IsNumeric as a dedicated function because of the declaration of i As Integer within For loop
                If IsNumeric(InputTextBox.Lines(i)) Then

                    ValidUserInput.Add(InputTextBox.Lines(i))

                Else
                    numberOfLines = numberOfLines - 1
                    LinesWithProblem = LinesWithProblem & (i + 1) & ", "
                    ResultForm.ErrorTextBox.Text = "ERROR: Invalid input at line " & LinesWithProblem & "invalid input ignored."
                End If
            Next

            If ValidUserInput.Count > 0 Then
                LowestNumber = ValidUserInput.Item(0)

                For Each ValidInput As Double In ValidUserInput
                    If ValidInput < LowestNumber Then
                        LowestNumber = ValidInput
                    End If
                Next
            End If

            ShowResultForm = True

            For j As Integer = 1 To InputTextBox.Lines.Length
                InputFromUser = InputFromUser & j & ".   " & InputTextBox.Lines(j - 1) & vbNewLine
            Next
            ResultForm.YourInputTextBox.Text = InputFromUser
            ResultForm.OutputTextBox.Text = FormatNumber(LowestNumber)
        End If

            If ShowResultForm = True Then
            ResultForm.Show()
        End If
    End Sub

End Class

 

 

To find highest number:

Spoiler

Public Class Form1

    Dim ShowResultForm As Boolean
    Dim HighestNumber As Double = 0
    Dim numberOfLines As Integer = 0
    Dim LinesWithProblem As String = ""
    Dim InputFromUser As String = ""

    Private Sub CalculateButton_Click(sender As Object, e As EventArgs) Handles CalculateButton.Click
        'Code to reset elements
        HighestNumber = 0
        ShowResultForm = False
        LinesWithProblem = ""
        numberOfLines = 0
        InputFromUser = ""

        ResultForm.ErrorTextBox.Text = "no error detected"

        'Function used to handle erroneous input, no input
        If InputTextBox.Text.Trim.Length <= 0 Then
            MessageBox.Show("ERROR : No input. Please input something.", "ERROR")
        Else

            Dim ValidUserInput As New List(Of Double)

            numberOfLines = InputTextBox.Lines.Length
            'For loop to run through every line of the multiline textbox
            For i As Integer = 0 To InputTextBox.Lines.Length - 1
                'Function used to handle erroneous input, only numbers
                'For IsNumeric to work with a multiline textbox, we must check line by line and not the entire textbox
                'Unable to have IsNumeric as a dedicated function because of the declaration of i As Integer within For loop
                If IsNumeric(InputTextBox.Lines(i)) Then

                    ValidUserInput.Add(InputTextBox.Lines(i))

                Else
                    numberOfLines = numberOfLines - 1
                    LinesWithProblem = LinesWithProblem & (i + 1) & ", "
                    ResultForm.ErrorTextBox.Text = "ERROR: Invalid input at line " & LinesWithProblem & "invalid input ignored."
                End If
            Next

            If ValidUserInput.Count > 0 Then
                HighestNumber = ValidUserInput.Item(0)

                For Each ValidInput As Double In ValidUserInput
                    If ValidInput > HighestNumber Then
                        HighestNumber = ValidInput
                    End If
                Next
            End If

            ShowResultForm = True

            For j As Integer = 1 To InputTextBox.Lines.Length
                InputFromUser = InputFromUser & j & ".   " & InputTextBox.Lines(j - 1) & vbNewLine
            Next
            ResultForm.YourInputTextBox.Text = InputFromUser
            ResultForm.OutputTextBox.Text = FormatNumber(HighestNumber)
        End If

            If ShowResultForm = True Then
            ResultForm.Show()
        End If
    End Sub

End Class

 

Changing a variable name and changing the operator is all the modification needed so that our program returns the highest number opposed to the lowest number.

 

Total:

Spoiler

Public Class Form1

    Dim ShowResultForm As Boolean
    Dim valueofthatline As Double = 0
    Dim totalofuserinput As Double = 0
    Dim numberOfLines As Integer = 0
    Dim LinesWithProblem As String = ""
    Dim InputFromUser As String = ""

    Private Sub CalculateButton_Click(sender As Object, e As EventArgs) Handles CalculateButton.Click
        'Code to reset elements

        ShowResultForm = False
        LinesWithProblem = ""
        numberOfLines = 0
        InputFromUser = ""

        ResultForm.ErrorTextBox.Text = "no error detected"

        'Function used to handle erroneous input, no input
        If InputTextBox.Text.Trim.Length <= 0 Then
            MessageBox.Show("ERROR : No input. Please input something.", "ERROR")
        Else

            Dim ValidUserInput As New List(Of Double)

            numberOfLines = InputTextBox.Lines.Length
            'For loop to run through every line of the multiline textbox
            For i As Integer = 0 To InputTextBox.Lines.Length - 1
                'Function used to handle erroneous input, only numbers
                'For IsNumeric to work with a multiline textbox, we must check line by line and not the entire textbox
                'Unable to have IsNumeric as a dedicated function because of the declaration of i As Integer within For loop
                If IsNumeric(InputTextBox.Lines(i)) Then

                    'Code to calculate the mean
                    valueofthatline = InputTextBox.Lines(i)
                    totalofuserinput += valueofthatline

                Else
                    numberOfLines = numberOfLines - 1
                    LinesWithProblem = LinesWithProblem & (i + 1) & ", "
                    ResultForm.ErrorTextBox.Text = "ERROR: Invalid input at line " & LinesWithProblem & "invalid input ignored."
                End If
            Next
            ShowResultForm = True

            For j As Integer = 1 To InputTextBox.Lines.Length
                InputFromUser = InputFromUser & j & ".   " & InputTextBox.Lines(j - 1) & vbNewLine
            Next
            ResultForm.YourInputTextBox.Text = InputFromUser
            ResultForm.OutputTextBox.Text = FormatNumber(totalofuserinput)
        End If

        If ShowResultForm = True Then
            ResultForm.Show()
        End If
    End Sub

End Class

 

Our code is much more simple now. The difference between the above code and the code used to search highest/lowest number is that we do not need to copy valid input into a seprate list before we can do the nessossary comparision/calculation.

 

Mean:

Spoiler

Public Class Form1

    Dim ShowResultForm As Boolean
    Dim valueofthatline As Double = 0
    Dim totalofuserinput As Double = 0
    Dim numberOfLines As Integer = 0
    Dim LinesWithProblem As String = ""
    Dim InputFromUser As String = ""

    Private Sub CalculateButton_Click(sender As Object, e As EventArgs) Handles CalculateButton.Click
        'Code to reset elements

        ShowResultForm = False
        LinesWithProblem = ""
        numberOfLines = 0
        InputFromUser = ""

        ResultForm.ErrorTextBox.Text = "no error detected"

        'Function used to handle erroneous input, no input
        If InputTextBox.Text.Trim.Length <= 0 Then
            MessageBox.Show("ERROR : No input. Please input something.", "ERROR")
        Else

            Dim ValidUserInput As New List(Of Double)

            numberOfLines = InputTextBox.Lines.Length
            'For loop to run through every line of the multiline textbox
            For i As Integer = 0 To InputTextBox.Lines.Length - 1
                'Function used to handle erroneous input, only numbers
                'For IsNumeric to work with a multiline textbox, we must check line by line and not the entire textbox
                'Unable to have IsNumeric as a dedicated function because of the declaration of i As Integer within For loop
                If IsNumeric(InputTextBox.Lines(i)) Then

                    'Code to calculate the mean
                    valueofthatline = InputTextBox.Lines(i)
                    totalofuserinput += valueofthatline

                Else
                    numberOfLines = numberOfLines - 1
                    LinesWithProblem = LinesWithProblem & (i + 1) & ", "
                    ResultForm.ErrorTextBox.Text = "ERROR: Invalid input at line " & LinesWithProblem & "invalid input ignored."
                End If
            Next
            ShowResultForm = True

            For j As Integer = 1 To InputTextBox.Lines.Length
                InputFromUser = InputFromUser & j & ".   " & InputTextBox.Lines(j - 1) & vbNewLine
            Next
            ResultForm.YourInputTextBox.Text = InputFromUser
            ResultForm.OutputTextBox.Text = FormatNumber(totalofuserinput/numberOfLines)
        End If

        If ShowResultForm = True Then
            ResultForm.Show()
        End If
    End Sub

End Class

 

We simply take the code used for total and modify one line of code.

 

Median:

Spoiler

Public Class Form1

    Dim ShowResultForm As Boolean
    Dim Median As String = 0
    Dim Num1 As Double = 0
    Dim Num2 As Double = 0
    Dim numberOfLines As Integer = 0
    Dim LinesWithProblem As String = ""
    Dim InputFromUser As String = ""

    Private Sub CalculateButton_Click(sender As Object, e As EventArgs) Handles CalculateButton.Click
        'Code to reset elements
        Median = 0
        Num1 = 0
        Num2 = 0
        ShowResultForm = False
        LinesWithProblem = ""
        numberOfLines = 0
        InputFromUser = ""

        ResultForm.ErrorTextBox.Text = "no error detected"

        'Function used to handle erroneous input, no input
        If InputTextBox.Text.Trim.Length <= 0 Then
            MessageBox.Show("ERROR : No input. Please input something.", "ERROR")
        Else

            Dim ValidUserInput As New List(Of Double)

            numberOfLines = InputTextBox.Lines.Length
            'For loop to run through every line of the multiline textbox
            For i As Integer = 0 To InputTextBox.Lines.Length - 1
                'Function used to handle erroneous input, only numbers
                'For IsNumeric to work with a multiline textbox, we must check line by line and not the entire textbox
                'Unable to have IsNumeric as a dedicated function because of the declaration of i As Integer within For loop
                If IsNumeric(InputTextBox.Lines(i)) Then

                    ValidUserInput.Add(InputTextBox.Lines(i))

                Else
                    numberOfLines = numberOfLines - 1
                    LinesWithProblem = LinesWithProblem & (i + 1) & ", "
                    ResultForm.ErrorTextBox.Text = "ERROR: Invalid input at line " & LinesWithProblem & "invalid input ignored."
                End If
            Next

            If ValidUserInput.Count > 0 Then

                ValidUserInput.Sort()

                If ValidUserInput.Count Mod 2 <> 0 Then 'uneven amount of numbers
                    Median = ValidUserInput.Item((ValidUserInput.Count \ 2))
                Else 'even amount of numbers
                    Num1 = ValidUserInput.Item((ValidUserInput.Count) \ 2)
                    MsgBox(Num1)
                    Num2 = ValidUserInput.Item(((ValidUserInput.Count) \ 2) - 1)
                    MsgBox(Num2)
                    Median = 0.5 * (Num1 + Num2)
                    MsgBox(Median)
                End If
            End If

                ShowResultForm = True

            For j As Integer = 1 To InputTextBox.Lines.Length
                InputFromUser = InputFromUser & j & ".   " & InputTextBox.Lines(j - 1) & vbNewLine
            Next
            ResultForm.YourInputTextBox.Text = InputFromUser
            ResultForm.OutputTextBox.Text = Median 'FormatNumber(median)
        End If

        If ShowResultForm = True Then
            ResultForm.Show()
        End If
    End Sub

End Class

 

 

Link to comment
Share on other sites

Link to post
Share on other sites

You should have done all the calculations in the first loop, where you test each line to see if it's numeric or not.

There, you can have a double variable and convert the line to double. Then do stuff with the variable.

- check if it's smaller or larger and update the min and max variables

- add the number to a sum

- maybe put the number into a separate array of numbers so you can sort them later

then calculate mean using sum / number of values

and for median, wouldn't you have to sort the array and then go in the middle of the array and get that number? If your numbers are not sorted by default, I don't think your function would be valid.

 

You have in one example Median variable defined as string, not sure that was correct. Probably works due to auto conversions but should check that.

 

Also a bit that's nagging me is ... get used to using Long instead of Integer. Integer is 16 bit wide, -32k to 32k , while long is 32 bit wide.

Also it makes more sense to use 32bit variables because in theory it's a bit faster, as modern processors have 32bit and 64bit registers. Of course, it's irrelevant for these small tiny applications, and .net stuff is interpreted anyway, so arguing about speed is ridiculous, but it's good to get into a habit, so that if and when you're gonna use other programming languages you'd do it by default the right way.

Link to comment
Share on other sites

Link to post
Share on other sites

54 minutes ago, mariushm said:

You should have done all the calculations in the first loop, where you test each line to see if it's numeric or not.

I would have liked to do all of my calculations in the first loop. However for lowest number and highest number, I needed something to start the compresion hence why I ended up extractiing all valid user input into a seprate list, then taking the first number from the list and start the comparison. 

 

58 minutes ago, mariushm said:

and for median, wouldn't you have to sort the array and then go in the middle of the array and get that number? If your numbers are not sorted by default, I don't think your function would be valid.

instead of using an array, I used a list since a list is dynamic while a array is static making declaration quite difficult. With the list, I sort it and take the middle of the list. 

 

54 minutes ago, mariushm said:

You have in one example Median variable defined as string, not sure that was correct. Probably works due to auto conversions but should check that.

If I declare as double that one variable, when I input 1,2,3,4

Instead of displaying 2.5, the way I want it to output.

It output 2. 

Link to comment
Share on other sites

Link to post
Share on other sites

1 hour ago, mariushm said:

and for median, wouldn't you have to sort the array and then go in the middle of the array and get that number? If your numbers are not sorted by default, I don't think your function would be valid.

exactly my thoughts you could sort the array from lowest to highest and get the lowest, highest and median in one got

 

 

Python: because quicker 

from random import randint
numbers = [randint(0, 100) for n in range(10)]

def quick_sort(array):
  if len(array)  <= 1:
    return array
  pivot = array[int(len(array)/ 2)]
  left = []
  middle = []
  right = []
  for number in array:
    if number > pivot:
      right.append(number)
    elif number < pivot:
      left.append(number)
    else:
      middle.append(number)
  return quick_sort(left) + middle + quick_sort(right)
    
processed_numbers = quick_sort(numbers)
print(f"lowest {processed_numbers[0]}")
print(f"highest {processed_numbers[-1]}")
print(f"median {processed_numbers[int(len(processed_numbers)/ 2)]}")
print(processed_numbers)

 

                     ¸„»°'´¸„»°'´ Vorticalbox `'°«„¸`'°«„¸
`'°«„¸¸„»°'´¸„»°'´`'°«„¸Scientia Potentia est  ¸„»°'´`'°«„¸`'°«„¸¸„»°'´

Link to comment
Share on other sites

Link to post
Share on other sites

1 hour ago, bindydad123 said:

I would have liked to do all of my calculations in the first loop. However for lowest number and highest number, I needed something to start the compresion hence why I ended up extractiing all valid user input into a seprate list, then taking the first number from the list and start the comparison. 

instead of using an array, I used a list since a list is dynamic while a array is static making declaration quite difficult. With the list, I sort it and take the middle of the list. 

 

If I declare as double that one variable, when I input 1,2,3,4

Instead of displaying 2.5, the way I want it to output.

It output 2. 

 

See the code below.

Your problems are related to not using proper data type conversion functions, and you have resizable arrays or Lists in VB without having to use controls on the form. 

The controls can be limited (in VB 6, the listbox could hold only 32768 entries, signed 16 bit value) and your code can be slower because the listbox only deals with strings, so you have some conversion to string and back to numbers.

In modern day with 4+ Ghz processors, it's not a big deal, but if you want to do it right, it's good to know these things.

 

Keep in mind that I wrote the code below directly in the forum here, without running it through VB.net so more than likely there's some errors in it, but if you get stuck somewhere google the keyword or ask here

 

'
' Note about ReDim .. a more modern approach is to use lists
' 
' dim numbers as New List(Of Double)() ... see http://vb.net-informations.com/collections/list.htm
'

dim min, max, sum, median, avg as double
dim isInitialized as boolean  ' if we have some initial values in min and max

dim numberList() as Double ' an array with unknown number of doubles 
dim numberMax as Long  ' maximum numbers we can store in array before we have to resize 
dim numberCount ' how many numbers are actually stored currently

' resize array to some value that's big enough initially but not big enough that 
' our application will use megabytes of memory. 10000 x 8 bytes ... good enough.
' 
' Every time you resize array, a new array is created and old array data is copied over 
' so you want to resize as little as possible if dealing with huge amounts of values
'
' Note that arrays usually start from 0, but the code below is easier if we start
' from 1, or just start from 0, but ignore the first array position. I start from 1.
' You can change the code to make it work from 0 if you really want to. 

ReDim numberList(1 to 10000)  ' no Preserve keyword, no previous elements in array  
numberCount = 0 ' no numbers in our array yet so just initialize this with 0

min=0
max=0
sum=0
avg=0
median=0
isInitialized = false


' ==== this is where you start to loop through lines === 

dim value as double
dim originalText as string
dim isDoubleValue as boolean

originalText = InputTextBox.Lines(i)
isDoubleValue = Double.TryParse(originalText,value)  ' try parse, if success put result in value and return true

if isDoubleValue then

' do stuff with the number that is now held in the value variable

	if isInitialized=false then
    	min = value
        max = value 
        isInitialized = true
        sum = sum + value
    else 
    	min = IF(value<min,value,min)
        max = IF(value>max,value,max)
        sum = sum + value
        
    end if 
    
    ' now put the actual value in the array
    numberCount = numberCount+1 ' increase the count 
    ' are we trying to put a number above our array, ex. at 10001 or 20001? 
    ' If so, resize base array by some amount but use Preserve keyword to save data
    if numberCount > numberMax then 
    	numberMax = numberMax + 10000
        ReDim Preserve NumberList(1 to numberMax) 
    end if 
    ' now we know for sure we can put value on position [numberCount] in array
    numberList[numberCount] = value

end if

' ==== this is where the for loop ends === 

' here, numberCount holds the actual amount of numbers in your double array

avg = sum / numberCount  ' if you started from 0, you'd have to say (numberCount+1)

'sort the numbers using most basic sorting algorithm 

dim isSorted as boolean
dim tempValue as Double

if numberCount > 1 then
	isSorted = false
    while (isSorted=false)
    	' assume that the array is sorted 
        isSorted = true
        ' use -1 because we compare current with next number so don't want to go with for all the way to last entry
        for i=1 to numberCount-1  
        	if numberList[i]>numberList[i+1] then
            	' we have to flip these two, so we'll have to do another loop
                isSorted = false
                ' flip these two numbers using a temporary variable
                tempValue = numberList[i]
                numberList[i] = numberList[i+1]
                numberList[i+1] = tempValue
            end if 
        next i 
    wend 
end if 

' your array is sorted so you can do the median ... 

 

And yes, if you do have to sort the array, then your min and max values will be first and last entries in the array, so you could skip those two if then else's in the loop, but they're so cheap in terms of cpu cycles that I don't care about it.

 

 

 

 

Link to comment
Share on other sites

Link to post
Share on other sites

If you want to code quickly, personally I stopped using arrays xD I started using Lists and Lists of Lists. I'm not saying it runs quicker, but it's easier to code. And then later I plan on converting the lists to arrays, when I feel like it or something. I just find them faster to code around than arrays. Maybe I'm doing arrays wrong though. lool.

*though I do still start off with arrays, but I usually convert them to lists later

Link to comment
Share on other sites

Link to post
Share on other sites

14 hours ago, McRo said:

If you want to code quickly, personally I stopped using arrays xD I started using Lists and Lists of Lists. I'm not saying it runs quicker, but it's easier to code. And then later I plan on converting the lists to arrays, when I feel like it or something. I just find them faster to code around than arrays. Maybe I'm doing arrays wrong though. lool.

*though I do still start off with arrays, but I usually convert them to lists later

totally agree

var numbers = new List<double>() { 1,55,12.3, ....};

var average = numbers.Average();
var min = numbers.Min();
var max = numbers.Max();
var sum = numbers.Sum();

 

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×