Resshantan Morgan
Resshantan Morgan

Reputation: 3

Vb.net how to display the frequency of digits from a text file

I am still studying this stuff and been looking through google and Youtube but there doesn't seem to have this problem for VB.net I saw some on python or Java though. This is the output that I have to get but when i read the text file and try to find the frequency its doesn't go as hoped

enter image description here

This is my code.

enter image description here

Imports System.IO
Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles btnDisplay.Click

        Dim reader As TextReader = New StreamReader("number.txt")
        Dim num As Integer = 0

        For Each item In reader.ReadToEnd
            If item.CompareTo(reader.ReadLine) = True Then
                num += 1
            End If

        Next

        rtbshow.Text = "Digit" & " " & " " & " Frequency " & vbNewLine & reader.ReadToEnd() & " " & " " & num

    End Sub
End Class

Upvotes: 0

Views: 362

Answers (3)

Joel Coehoorn
Joel Coehoorn

Reputation: 415665

A dictionary can work for this, but given just the nine digits an indexed array can do just as well and probably be faster.

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles btnDisplay.Click
    Dim digitCounts = Enumerable.Repeat(0,10).ToArray()

    Dim digits = File.ReadAllText("number.txt").
                   Where(Function(c) Char.IsDigit(c)).
                   Select(Function(c) Asc(c) - Asc("0"c))
    For Each d As Integer In digits
        digitCounts(d) += 1
    Next
    Dim result As New StringBuilder($"Digit{vbTab}Frequency{vbCrLf}")
    For i As Integer = 0 To 9
        result.AppendLine($"{i,3}{vbTab}{digitCounts(i),7}")
    Next
    rtbshow.Text = result.ToString()
End Sub

You can (kind of) see it working here, except I couldn't get .Net fiddle to do the string interpolation:

https://dotnetfiddle.net/FMWnMg

We could also solve this with a GroupBy() operation:

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles btnDisplay.Click
    Dim result As New StringBuilder($"Digit{vbTab}Frequency{vbCrLf}")
    Dim digits = File.ReadAllText("number.txt").
             Where(Function(c) Char.IsDigit(c)).
             OrderBy(Function(d) d).
             GroupBy(Function(d) d, 
                     Function(d, g) $"{d,3}{vbTab}{g.Count(),7}{vbCrLf}"
             )
    
    For Each d As String in digits
        result.Append(d)
    Next
    rtbshow.Text = result.ToString()
End Sub

See it work here:

https://dotnetfiddle.net/Xxl2z3

Note this last skips missing digits.

Upvotes: 1

Andrew Morton
Andrew Morton

Reputation: 25013

A Dictionary provides a convenient entity to store the (digit, count_of_digit) data.

Then you just need to go through all the characters in the file and check if each one is a digit. If it is, then add one to the count_of_digit for that digit.

This is an example using a Console Application:

Imports System.IO

Module Module1

    Sub CreateTestFile(s As String)
        Dim rand As New Random()

        Using sw As New StreamWriter(s)
            For i = 1 To 10000
                sw.Write(rand.Next(0, 10).ToString())
            Next
        End Using

    End Sub

    Function GetNumberFrequencies(s As String) As Dictionary(Of Integer, Integer)
        Dim nf As New Dictionary(Of Integer, Integer)
        For i = 0 To 9
            nf.Add(i, 0)
        Next

        Using sr As New StreamReader(s)
            While Not sr.EndOfStream
                Dim line = sr.ReadLine()
                For Each c In line
                    If c >= "0" AndAlso c <= "9" Then
                        ' A quick way to convert the strings "0"-"9" to the numbers 0-9:
                        Dim index = AscW(c) - AscW("0)")
                        nf(index) += 1
                    End If
                Next
            End While
        End Using

        Return nf

    End Function

    Sub Main()
        ' Always specify a full path to a file that you use.
        Dim testFile = "C:\temp\randNums.txt"
        CreateTestFile(testFile)
        Dim nf = GetNumberFrequencies(testFile)

        For Each kvp As KeyValuePair(Of Integer, Integer) In nf
            Console.WriteLine(kvp.Key & " - " & kvp.Value)
        Next

        Console.ReadLine()

    End Sub

End Module

Sample output:

0 - 1013
1 - 963
2 - 991
3 - 1033
4 - 1001
5 - 966
6 - 962
7 - 1006
8 - 1018
9 - 1047

To use the GetNumberFrequencies function on a form, you could:

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles btnDisplay.Click
    Dim testFile = "C:\temp\randNums.txt"
    Dim nf = GetNumberFrequencies(testFile)
    Dim sb As New Text.Stringbuilder("Digit   Frequency" & VbNewLine)

    For Each kvp As KeyValuePair(Of Integer, Integer) In nf
        sb.Append(kvp.Key & "      " & kvp.Value & VbNewLine)
    Next

    rtbshow.Text = sb.ToString()

End Sub

Upvotes: 2

Mary
Mary

Reputation: 15091

File.ReadAllText returns everything in the file as a string. Next we declare some variables to hold the number of occurrences of each digit. A String in .net is also an array of Char. We can take advantage of this by using a For Each loop to check each character in the file, one by one. First, with a method of the Char class, we check IsDigit. If True we pick which Integer variable to increment with a Select Case.

Zero += 1

is a shortcut way to write

Zero = Zero + 1

Finally, we write the string to display the results. The $ in front of the String means it is an interpolated string. You can insert variable directly into the string surrounded by braces, { }. This replaces String.Format or a dizzying number of quotes and ampersands. In recent versions of Visual Studio you can hit Enter to indicate a new line without having to enter any new line characters.

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim FileContents = File.ReadAllText("numbers.txt")
    Dim Zero, One, Two, Three, Four, Five, Six, Seven, Eight, Nine As Integer
    For Each c In FileContents
        If Char.IsDigit(c) Then
            Select Case c
                Case "0"c
                    Zero += 1
                Case "1"c
                    One += 1
                Case "2"c
                    Two += 1
                Case "3"c
                    Three += 1
                Case "4"c
                    Four += 1
                Case "5"c
                    Five += 1
                Case "6"c
                    Six += 1
                Case "7"c
                    Seven += 1
                Case "8"c
                    Eight += 1
                Case "9"c
                    Nine += 1
            End Select
        End If
    Next
    Dim DisplayResults = $"0    {Zero}
1    {One}
2    {Two}
3    {Three}
4    {Four}
5    {Five}
6    {Six}
7    {Seven}
8    {Eight}
9    {Nine}"
    MessageBox.Show(DisplayResults)
End Sub

Upvotes: 0

Related Questions