Hi guys, I'm having some problems with sum of array values and I hope you can help me out. I have a form from which there are multiple values added and saved to txt file. Than on button click, these values are read from txt file to array and shown in listbox2. Now there are date, some true/false value,...whats important to me that there are some, let's say "employees listed in the ListBox1. There's numeric up/down on the form.

Now what I want in my listbox2 is in first column the name of employee that was chosen in the Listbox1 and the number that was selected in the numeric up/down. Now in array the names of employees can repeat, I want the sum of all values that were chosen in numeric up/down for each employee. And at the end I need total sum of all the values from numeric up/down.

This is my code:

Imports System.IO

Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        ListBox1.Items.Add("Mercedes")
        ListBox1.Items.Add("Citroen")
        ListBox1.Items.Add("BMW")
        ListBox1.Items.Add("Opel")
        ListBox1.Items.Add("Renault")

    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click

        Dim table1()

        Dim tablefull As Boolean

        If Not tablefull Then
            ReDim table1(0)
            tablefull = True
        Else

            ReDim Preserve table1(UBound(table1) + 1)

        End If

        Dim date_short As String
        date_short = Format(DateTimePicker1.Value, "dd/MM/yyyy")

        Dim placano As String

        If CheckBox1.Checked = True Then
            placano = "True"
        Else
            placano = "False"
        End If

        Dim work_done As Integer
        work_done = NumericUpDown1.Value

        Dim status As Integer

        If RadioButton1.Checked = True Then
            status = "1"
        ElseIf RadioButton2.Checked = True Then
            status = "2"
        ElseIf RadioButton3.Checked = True Then
            status = "3"
        End If

        Dim data1 As System.IO.StreamWriter

        data1 = New System.IO.StreamWriter("\data.txt", True)

        data1.Write(date_short & vbTab)
        data1.Write(placano & vbTab)
        data1.Write(ListBox1.SelectedIndex & vbTab)
        data1.Write(work_done & vbTab)
        data1.Write(status)
        data1.WriteLine()

        data1.Close()

    End Sub


    Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click

        Dim FileName As String = "\data.txt"
        Dim table1() As String = File.ReadAllLines(FileName)

        ListBox2.Items.Clear()
        For Each obj As Object In table1

            ListBox2.Items.Add(obj)
        Next

        Dim RowCount = table1.GetUpperBound(0) - 1
        Dim ColumnCount = table1.GetUpperBound(1) - 1

    End Sub

End Class

I hope I did explain well and that I didn't complicate 2 much.

I want also the results in the listbox2 to look "cosmetic" and add columt names, some stripes so separate rows, in the total sum of numeric up/down to write "Total:". Is this a thing of an array or does it need to be set in Listbox?

tnx a lot

Recommended Answers

All 13 Replies

Why are you using a ListBox instead of a ListView? The ListView is designed for columns and headers, but the Listbox is not.

Ok, I didn't know that. I'will use listview instead. But I still need to show calculate an array and populate it into listview. My txt file look something like this:

Opel      5
BMW       7
Renault  12
Opel      3
Renault   6

How to calculate in array so it shows me like this in the listview:

Opel      8
BMW       7
Renault  18
SUM      33

thanks

Basically use the items collection of the listview. Read each line of the text file and parse it. Check if the name part already exists. If it does, add the new value to the old value. If it doesn't, create a new item. Keep a running totaL, then add a new item at the end with the grand total. If you need the info in a new file, iterate through the items and write the info to a file.

thx for the info...yes, that would be one of the ways to get the result. But what if I must do it via calculate with array values? It's a school project and they require to calculate values with the array.

If you use a Dictionary (also known as an associative array) you can do the following:

Dim cars As New Dictionary(Of String, Integer)

For Each item As String In {"Opel,5", "BMW,7", "Renault,12", "Opel,3", "Renault,6"}

    Dim flds() As String = item.Split(",")
    Dim car As String = flds(0)
    Dim num As Integer = CInt(flds(1))

    'If the car is already in the dictionary then add the new number
    'to the total, otherwise add the new car name and number.

    If cars.ContainsKey(car) Then
        cars(car) += num
    Else
        cars.Add(car, num)
    End If

Next

'Populate the listview with the unique car data

For Each car As String In cars.Keys
    lvwCars.Items.Add(New ListViewItem({car, cars(car)}))
Next

Just replace the For line to read from a file instead of a string. If you need to persist the values in the dictionary then move it to the class level.

Here are 3 different versions.

  • Version 1 uses the dictionary above, mentioned by Reverend Jim.
  • Version 2 uses two arrays.
  • Version 3 uses an array of a class.

Note: Uses a ListView as mentioned by tinsaafl

Controls on form:

  • Button named writeBtn
  • Button named readBtn
  • CheckBox named CheckBox1
  • DateTimePicker named DateTimePicker1
  • NumericUpDown named NumericUpDown1
  • Panel named Panel1
  • RadioButton named RadioButton1
  • RadioButton named RadioButton2
  • RadioButton named RadioButton3
  • ListBox named ListBox1
  • ListView named ListView1
  • ListView named ListView2

Note: Place RadioButtion1, RadioButton2, and RadioButton3 on Panel1.

I have declared the filename a private variable so that it is not hard coded multiple times throughout the program.

Private _filename As String = My.Computer.FileSystem.SpecialDirectories.MyDocuments & "\data.txt"

Form1_Load:

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

    ListBox1.Items.Add("Mercedes")
    ListBox1.Items.Add("Citroen")
    ListBox1.Items.Add("BMW")
    ListBox1.Items.Add("Opel")
    ListBox1.Items.Add("Renault")


    'set View to Details
    ListView1.View = View.Details
    ListView1.Columns.Add("Date", 80, HorizontalAlignment.Left)
    ListView1.Columns.Add("Placano", 60, HorizontalAlignment.Left)
    ListView1.Columns.Add("Car", 60, HorizontalAlignment.Left)
    ListView1.Columns.Add("Work Done", 80, HorizontalAlignment.Left)
    ListView1.Columns.Add("Status", 60, HorizontalAlignment.Left)

    'set View to Details
    ListView2.View = View.Details
    ListView2.Columns.Add("Car", 60, HorizontalAlignment.Left)
    ListView2.Columns.Add("Total", 60, HorizontalAlignment.Left)
End Sub

writeBtn_Click:

Private Sub writeBtn_Click(sender As Object, e As EventArgs) Handles writeBtn.Click
    writeData()
End Sub

readBtn_Click:

Private Sub readBtn_Click(sender As Object, e As EventArgs) Handles readBtn.Click
    readData()
End Sub

writeData:

Private Sub writeData

        Dim tableArr()

        Dim tableArrfull As Boolean

        If Not tableArrfull Then
            ReDim tableArr(0)
            tableArrfull = True
        Else

            ReDim Preserve tableArr(UBound(tableArr) + 1)

        End If

        Dim date_short As String
        date_short = Format(DateTimePicker1.Value, "dd/MM/yyyy")

        Dim placano As String

        If CheckBox1.Checked = True Then
            placano = "True"
        Else
            placano = "False"
        End If

        Dim work_done As Integer
        work_done = NumericUpDown1.Value

        Dim status As Integer

        If RadioButton1.Checked = True Then
            status = "1"
        ElseIf RadioButton2.Checked = True Then
            status = "2"
        ElseIf RadioButton3.Checked = True Then
            status = "3"
        End If

        If String.IsNullOrEmpty(ListBox1.Text) Then
            MessageBox.Show("Car not selected. Please select a car and try again.", "Car not selected", MessageBoxButtons.OK, MessageBoxIcon.Error)
        Else

            Dim data1 As System.IO.StreamWriter

            data1 = New System.IO.StreamWriter(_filename, True)


            data1.Write(date_short & vbTab)
            data1.Write(placano & vbTab)
            'data1.Write(ListBox1.SelectedIndex & vbTab)
            data1.Write(ListBox1.Text & vbTab)
            data1.Write(work_done & vbTab)
            data1.Write(status)
            data1.WriteLine()

            data1.Close()
        End If
    End Sub

Version 1 (using Dictionary):

readData:

Private Sub readData()
    Dim cars As New Dictionary(Of String, Integer)

    'total # of columns
    Dim totalColumns As Integer = 5

    Dim fileDataArr() As String = File.ReadAllLines(_filename)

    ListView1.Items.Clear()
    For Each line As String In fileDataArr

        'skip any blank lines
        If Not String.IsNullOrEmpty(line) Then
            Dim flds() As String = line.Split(vbTab)

            If flds.Count = totalColumns Then
                Dim entryDate As String = flds(0)
                Dim placano As String = flds(1)
                Dim car As String = flds(2)
                Dim workDone As Integer = flds(3)
                Dim status As String = flds(4)

                ListView1.Items.Add(New ListViewItem({entryDate, placano, car, workDone, status}))

                'if car exists in dictionary
                'add value to existing value.
                'Otherwise, add car to the 
                'dictionary with its value.
                If cars.ContainsKey(car) Then
                    cars(car) += workDone
                Else
                    cars.Add(car, workDone)
                End If
            Else
                MessageBox.Show("Invalid data found in file. Found " & flds.Count & " columns. Expecting " & totalColumns & ". Skipping.", "Invalid Data Found", MessageBoxButtons.OK, MessageBoxIcon.Warning)
            End If
        End If
    Next

    'clear previous items
    ListView2.Items.Clear()

    For Each car As String In cars.Keys
        ListView2.Items.Add(New ListViewItem({car, cars(car)}))
    Next
End Sub

Alternatively, instead of:

For Each car As String In cars.Keys
    ListView2.Items.Add(New ListViewItem({car, cars(car)}))
Next

You could also do the following:

For Each car As KeyValuePair(Of String, Integer) In cars
    ListView2.Items.Add(New ListViewItem({car.Key, car.Value}))
Next

Version 2 (using two arrays):

readData:

Private Sub readData()

    Dim cars() As String = {}
    Dim carsTotals() As Integer = {}

    'total # of columns
    Dim totalColumns As Integer = 5

    Dim fileDataArr() As String = File.ReadAllLines(_filename)

    ListView1.Items.Clear()
    For Each line As String In fileDataArr

        'skip any blank lines
        If Not String.IsNullOrEmpty(line) Then
            Dim flds() As String = line.Split(vbTab)

            If flds.Count = totalColumns Then
                Dim entryDate As String = flds(0)
                Dim placano As String = flds(1)
                Dim car As String = flds(2)
                Dim workDone As Integer = flds(3)
                Dim status As String = flds(4)

                ListView1.Items.Add(New ListViewItem({entryDate, placano, car, workDone, status}))

                Dim carExists As Boolean = False
                Dim carIndex As Integer = 0

                'check if car exists in cars array
                If (cars.Length > 0) Then
                    For i As Integer = 0 To cars.Length - 1
                        If cars(i) = car Then
                            carExists = True
                            carIndex = i
                        End If
                    Next
                End If

                'if car exists in array
                'add value to existing value.
                'Otherwise, add car to the 
                'array and its value to 
                'carTotals

                If carExists = True Then
                    carsTotals(carIndex) += workDone
                Else

                    'resize arrays
                    ReDim Preserve cars(UBound(cars) + 1)
                    ReDim Preserve carsTotals(UBound(carsTotals) + 1)

                    cars(UBound(cars)) = car
                    carsTotals(UBound(carsTotals)) = workDone
                End If
            Else
                MessageBox.Show("Invalid data found in file. Found " & flds.Count & " columns. Expecting " & totalColumns & ". Skipping.", "Invalid Data Found", MessageBoxButtons.OK, MessageBoxIcon.Warning)
            End If
        End If
    Next

    'clear previous items
    ListView2.Items.Clear()

    For i As Integer = 0 To cars.Count - 1
        'add items to ListView2
        ListView2.Items.Add(New ListViewItem({cars(i), carsTotals(i)}))
    Next
End Sub

Alternatively, instead of:

'resize arrays
ReDim Preserve cars(UBound(cars) + 1)
ReDim Preserve carsTotals(UBound(carsTotals) + 1)

cars(UBound(cars)) = car
carsTotals(UBound(carsTotals)) = workDone

You can do the following:

'resize arrays
ReDim Preserve cars(cars.Length)
ReDim Preserve carsTotals(carsTotals.Length)

'add car to cars array
cars(cars.Length - 1) = car

'add total to carsTotals
carsTotals(carsTotals.Length - 1) = workDone

Version 3 (using a custom class):

First let's define our custom class:

CarInfo.vb

Public Class CarInfo
    Public Property name As String
    Public Property total As Integer
End Class

readData:

Private Sub readData()

    Dim cars() As CarInfo = {}

    'total # of columns
    Dim totalColumns As Integer = 5

    Dim fileDataArr() As String = File.ReadAllLines(_filename)

    ListView1.Items.Clear()

    For Each line As String In fileDataArr

        'skip any blank lines
        If Not String.IsNullOrEmpty(line) Then
            Dim flds() As String = line.Split(vbTab)

            If flds.Count = totalColumns Then
                Dim entryDate As String = flds(0)
                Dim placano As String = flds(1)
                Dim car As String = flds(2)
                Dim workDone As Integer = flds(3)
                Dim status As String = flds(4)

                ListView1.Items.Add(New ListViewItem({entryDate, placano, car, workDone, status}))

                Dim carExists As Boolean = False
                Dim carIndex As Integer = 0

                'IsArray will be False until
                'cars is given a size using
                'ReDim or is declared using
                'some version of = {}
                If IsArray(cars) = True Then
                    'check if car exists in cars array
                    If (cars.Length > 0) Then
                        For i As Integer = 0 To cars.Length - 1
                            If cars(i).name = car Then
                                carExists = True
                                carIndex = i
                            End If
                        Next
                    End If
                End If

                'if car exists in array
                'add value to existing value.
                'Otherwise, add car to the 
                'array and its value to 
                'carTotals
                If carExists = True Then
                    cars(carIndex).total += workDone
                Else

                    'resize arrays

                    'IsArray will be False until
                    'cars is given a size using
                    'ReDim or is declared using
                    'some version of = {}
                    If IsArray(cars) Then
                        ReDim Preserve cars(UBound(cars) + 1)
                    Else
                        ReDim cars(0)
                    End If

                    'instantiate cars(UBound(cars))
                    cars(UBound(cars)) = New CarInfo

                    cars(UBound(cars)).name = car
                    cars(UBound(cars)).total = workDone
                End If
            Else
                MessageBox.Show("Invalid data found in file. Found " & flds.Count & " columns. Expecting " & totalColumns & ". Skipping.", "Invalid Data Found", MessageBoxButtons.OK, MessageBoxIcon.Warning)
            End If
        End If
    Next

    'clear previous items
    ListView2.Items.Clear()

    For i As Integer = 0 To cars.Count - 1
        'add items to ListView2
        ListView2.Items.Add(New ListViewItem({cars(i).name, cars(i).total}))
    Next
End Sub

Resources:
How to: Add Columns to the Windows Forms ListView Control

Listview - adding data

If your teacher asked you to use an array, it is probably better to not use a Dictionary.

Dictionary<TKey, TValue> Class

Represents a collection of keys and values.

It exists in the System.Collections.Generic namespace.

Here is another version that uses List--just to show another way to do it.

Version 4 (using List):

We will use our custom class "CarInfo".

CarInfo.vb

Public Class CarInfo
    Public Property name As String
    Public Property total As Integer
End Class

readData:

Private Sub readData()

    Dim cars As New List(Of CarInfo)

    'total # of columns
    Dim totalColumns As Integer = 5

    Dim fileDataArr() As String = File.ReadAllLines(_filename)

    ListView1.Items.Clear()

    For Each line As String In fileDataArr

        'skip any blank lines
        If Not String.IsNullOrEmpty(line) Then
            Dim flds() As String = line.Split(vbTab)

            If flds.Count = totalColumns Then
                Dim entryDate As String = flds(0)
                Dim placano As String = flds(1)
                Dim car As String = flds(2)
                Dim workDone As Integer = flds(3)
                Dim status As String = flds(4)

                ListView1.Items.Add(New ListViewItem({entryDate, placano, car, workDone, status}))

                Dim carExists As Boolean = False
                Dim carIndex As Integer = 0

                'check if car exists in cars array
                If (cars.Count > 0) Then
                    For i As Integer = 0 To cars.Count - 1
                        If cars(i).name = car Then
                            carExists = True
                            carIndex = i
                        End If
                        Next
                End If


                'if car exists in List
                'add value to existing value.
                'Otherwise, add car
                If carExists = True Then
                    cars(carIndex).total += workDone
                Else

                    Dim myCarInfo As New CarInfo
                    myCarInfo.name = car
                    myCarInfo.total = workDone

                    cars.Add(myCarInfo)
                End If
            Else
                MessageBox.Show("Invalid data found in file. Found " & flds.Count & " columns. Expecting " & totalColumns & ". Skipping.", "Invalid Data Found", MessageBoxButtons.OK, MessageBoxIcon.Warning)
            End If
        End If
    Next

    'clear previous items
    ListView2.Items.Clear()

    For i As Integer = 0 To cars.Count - 1
        'add items to ListView2
        ListView2.Items.Add(New ListViewItem({cars(i).name, cars(i).total}))
    Next
End Sub

If we add our own constructor to "CarInfo.vb"

CarInfo.vb

Public Class CarInfo
    Public Property name As String
    Public Property total As Integer

    'constructor
    Public Sub New()
    End Sub

    'constructor
    Public Sub New(ByVal name As String, ByVal total As String)
        Me.name = name
        Me.total = total
    End Sub
End Class

then we can replace the following lines of code (above):

Dim myCarInfo As New CarInfo
myCarInfo.name = car
myCarInfo.total = workDone

cars.Add(myCarInfo)

With this line:

cars.Add(New CarInfo(car, workDone))

OMG guys what an effort you put into this! Thank you a Reverend Jim and THANK YOU cgeier!

Because my assignment requires to user an array, I decided to user your method nr.2. I must say, it works like a charm! :) I am so impressed with your posts that I'm embarrased to ask another thing, the only thing that is missing and I can't figure out;

in the listview2, I need to get the "total of the totals". Listview2 looks like this:

Car     Total
BMW     25
Renault 6
Opel    14
Mercedes 5

and I need the total sum in the last line, possibly with the line above:

Car     Total
BMW     25
Renault 6
Opel    14
Mercedes 5
_________________
TOTAL   50

How can I do this?

Use a variable to sum the totals as you add them to listview2. Then after the for loop add a series of '-' (dashes) in each column of a new row. Then add one more row with the total of the totals. I'll leave the implementation to you.

Hi, I get the wanted result by this:

For i As Integer = 0 To cars.Count - 1
'add items to List
ListView2.Items.Add(New ListViewItem({cars(i), carsTotals(i)}))

carsTotals1 = carsTotals(0) + carsTotals(1) + carsTotals(2) + carsTotals(3) + carsTotals(4)

Next

ListView2.Items.Add(New ListViewItem({"Total:", carsTotals1}))

but how can I avoid listing all "carstotals(0),.... like I did above?

Use a pen and paper and step through your code to see what is happening--to see what the computer sees.

will do, I'm sure I'll manage somehow. Thanks all for your help! ;)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.