Home > Enterprise >  Fill in missing numbers in different lists twice. ArgumentOutOfRangeException
Fill in missing numbers in different lists twice. ArgumentOutOfRangeException

Time:12-03

I need your help to prepare data. I am reading a byte array. I make bytes to unsigned integers. I read in different blocks of that array and write the UInt32s in 5 lists in total. The data has been stored compressed; that is, some spaces are missing and I need to fill them up. To make it clear, I made a compilable test project for you and wrote the data into an excel file.

This is the original data.
From the left to the right: Sizes, Addresses, Indexes, Number_of_items, Description
This is the original file.
You can see that in column C the 2, 3, and 4 are missing. So I select columns C through E, and move them down 3 rows. I fill the gaps with 2, 3, 4 in column C and 1, 1, 1 in the other two columns. enter image description here
I do this until I reach the end of column B. Columns B, C, D, and E must have the same length. enter image description here

Where I have a little problem

I fail because a While or For loop evaluates the List.Count property only once. That is, if I add something to a list within the loop, the loop doesn't run often enough. I've provisionally worked around this by writing While True and catching an OutOfRangeException. Maybe someone has a better idea; or even an idea that completely replaces my approach :D

Step № 2

If a row has a 2 in column D, I select columns B through E below the 2, and move the contents down one row (only one, because the difference is 1). enter image description here

I want to do this until I get to the bottom of the table. This will make all columns the same length. enter image description here
Again, I have the problem that I use While True and go out using an exception. Does anyone have a better idea?

FormMain.vb

Public NotInheritable Class FormMain
    Private Sizes As New List(Of UInt32) From {
        58_355UI,
20_270UI,
4_830UI,
4_443UI,
25_177UI,
8_844UI,
4_101UI,
4_200UI,
14_991UI,
12_639UI,
12_894UI,
14_165UI,
12_954UI,
26_670UI,
7_388UI}

    Private Addresses As New List(Of UInt32) From {4_323UI, 62_706UI, 83_646UI, 88_935UI, 93_883UI, 128_259UI, 132_718UI,
        137_254UI, 152_590UI, 178_485UI, 193_022UI, 206_718UI}

    Private Indexes As New List(Of UInt32) From {1UI, 5UI, 6UI, 9UI, 10UI, 12UI}

    Private NumberOfItems As New List(Of UInt32) From {1UI, 2UI, 1UI, 2UI, 1UI, 2UI}
    Private Description As New List(Of UInt32) From {1UI, 1UI, 1UI, 1UI, 1UI, 1UI}
    Private Sub ButtonStart_Click(sender As Object, e As EventArgs) Handles ButtonStart.Click
        Dim RopD As New Reprocessing_of_parsed_data(Sizes, Addresses, Indexes, NumberOfItems, Description)
        RopD.Fill_gaps()
    End Sub
End Class

Reprocessing_of_parsed_data.vb

Public NotInheritable Class Reprocessing_of_parsed_data
    Public Property Sizes As New List(Of UInteger)
    Public Property Addresses As New List(Of UInteger)
    Public Property Indexes As New List(Of UInteger)
    Public Property Number_of_items As New List(Of UInteger)
    Public Property Description As New List(Of UInteger)

    Public Sub New(sizes As List(Of UInt32), addresses As List(Of UInt32), indexes As List(Of UInt32), number_of_items As List(Of UInt32), description As List(Of UInt32))
        Me.Sizes = sizes
        Me.Addresses = addresses
        Me.Indexes = indexes
        Me.Number_of_items = number_of_items
        Me.Description = description
    End Sub

    Public Sub Fill_gaps()
        Dim counterForAddressesList As Integer = 0
        'Dim ListCount As Integer = Indexes.Count - 2
        Dim i As Integer = 0
        While True 'i < ListCount - 2
            Try
                Dim delta As Integer = CInt(Indexes(i   1) - Indexes(i)) - 1
                Dim number As UInt32 = Indexes(i)
                While delta > 0
                    number  = 1UI
                    counterForAddressesList  = 1
                    Indexes.Insert(CInt(number) - 1, number)
                    Number_of_items.Insert(CInt(number) - 1, 1UI)
                    Description.Insert(CInt(number) - 1, 1UI)
                    delta -= 1
                    'ListCount  = 1
                End While
                counterForAddressesList  = 1
                i  = 1
            Catch ex As ArgumentOutOfRangeException
                Exit While
            End Try
        End While

        ' Step 2

        Dim j As Integer = 0
        While True
            Try
                If Number_of_items(j) > 1UI Then
                    Dim delta As Integer = CInt(Number_of_items(j)) - 1
                    While delta > 0
                        Addresses.Insert(j   1, UInteger.MaxValue)
                        Indexes.Insert(j   1, UInteger.MaxValue)
                        Number_of_items.Insert(j   1, UInteger.MaxValue)
                        Description.Insert(j   1, UInteger.MaxValue)
                        delta -= 1
                        j  = 1
                    End While
                End If
                j  = 1
            Catch ex As ArgumentOutOfRangeException
                Exit While
            End Try
        End While

    End Sub
End Class

CodePudding user response:

It is never a good idea to catch an index out of bounds exception in a Try-Catch-statement. Only conditions you are not in control of (often I/O errors) should be handled at runtime. An index being out of bounds is a design error and must be fixed at design time.

I extracted the two steps from Sub Fill_gaps into two new methods to make the code easier to read and test.

Public Sub Fill_gaps() ' A better name would be "Decompress"
    PrintTable() 'For testing
    FillGaps()
    PrintTable() 'For testing
    AddMissingNumberOfItems()
    PrintTable() 'For testing
End Sub

I also added a method PrintTable for testing

Private Sub PrintTable()
    Console.WriteLine()
    Console.WriteLine($"       A         B         C         D         E")
    For i = 0 To Sizes.Count - 1
        Dim A = Sizes(i)
        Dim B = If(i < Addresses.Count, Addresses(i), 0UI)
        Dim C = If(i < Indexes.Count, Indexes(i), 0UI)
        Dim D = If(i < NumberOfItems.Count, NumberOfItems(i), 0UI)
        Dim E = If(i < Description.Count, Description(i), 0UI)
        Console.WriteLine($"{A,10}{B,10}{C,10}{D,10}{E,10}")
    Next
End Sub

Step 1: fill the gaps (the method is self-explanatory):

Private Sub FillGaps()
    ' Fill gaps in columns C, D and E.
    ' The number of Addresses B indicates the total number of indexes.
    ' Append empty items to C, D and E until the list counts matches the
    ' expected total number of indexes.
    Dim originalIndexCount = Indexes.Count 'Save original count
    Do While Indexes.Count < Addresses.Count
        Indexes.Add(CUInt(Indexes.Count   1)) ' Make index 1-based
        NumberOfItems.Add(1)
        Description.Add(1)
    Loop

    'Move the rows to where the index indicates.
    'We do it backwards to not overwrite existing items.
    For i As Integer = originalIndexCount - 1 To 0 Step -1
        Dim targetIndex = CInt(Indexes(i)) - 1 ' Subtract 1, indexes are 0-based

        If targetIndex <> i Then
            ' Copy to target position
            Indexes(targetIndex) = Indexes(i)
            NumberOfItems(targetIndex) = NumberOfItems(i)
            Description(targetIndex) = Description(i)

            'Clear resp. initialize old row
            Indexes(i) = CUInt(i   1) ' Make index 1-based
            NumberOfItems(i) = 1
            Description(i) = 1
        End If
    Next
End Sub

Step 2:

Private Sub AddMissingNumberOfItems()
    ' Insert empty rows after items with NumberOfItems > 1.
    ' We do it backwards to not mess up our indexes.
    For i As Integer = Indexes.Count - 1 To 0 Step -1
        For k As UInteger = 2 To NumberOfItems(i)
            Addresses.Insert(i   1, 0)
            Indexes.Insert(i   1, 0)
            NumberOfItems.Insert(i   1, 0)
            Description.Insert(i   1, 0)
        Next
    Next
End Sub

If you use the following test list for the descriptions, you will better see which rows have been moved or added

Private Description As New List(Of UInt32) From {2UI, 3UI, 4UI, 5UI, 6UI, 7UI}
  • Related