Search code examples
arraysexcelvbavariant

VBA: Run through a 2D Variant Array deleting rows


I am importing a range as a 2D Variant into VBA and to declare an array as Variant by `Dim matrix().

I now want to loop through the rows and delete rows where the 2nd column = "even" or the 5th row ends with "_tom". Dataset below

My main issue is that I do not know how to delete that rows?

1,  odd,    3,  27, today
2,  even,   6,  21, today_tom
3,  odd,    9,  28, today
4,  even,   12, 30, today
5,  odd,    15, 17, today_tom
6,  even,   18, 17, today
7,  odd,    21, 18, today
8,  even,   24, 9 , today_tom
9,  odd,    27, 24, today_tom
10, even,   30, 9,  today
11, odd,    33, 11, today
12, even,   36, 22, today
13, odd,    39, 8 , today
14, even,   42, 1 , today
15, odd,    45, 4 , today

Current code:

Sub test()
    Dim matrix As Variant
    matrix = Range("A1:E15")
    Dim r As Long

    For r = LBound(matrix, 1) To UBound(matrix, 1)
        If matrix(r, 2).Value = "even" Then
            'delete
        End If
        If Right(matrix(r, 2).Value, 4) = "_tom" Then
            'delete
        End If
    Next r

End Sub


Solution

  • Delete array elements via Application.Index()

    Yes, it's possible to "delete" array elements by a workaround via the Application.Index function enriched by several array arguments:

    
    Sub Restructure()
    ' Site: https://stackoverflow.com/questions/59685516/vba-run-through-a-2d-variant-array-deleting-columns
        Dim matrix As Variant
        matrix = Sheet1.Range("A1:E15")
        '========================================================
        'Maintain only array rows <> "even" or ending with "_tom"
        '--------------------------------------------------------
        matrix = Application.Index(matrix, getRowNo(matrix), Array(1, 2, 3, 4, 5))
    
    ''optional: write to any target range    
    '           Sheet1.Range("G1").Resize(UBound(matrix), UBound(matrix, 2)) = matrix
    End Sub
    

    Helper function getRowNo()

    Function getRowNo(arr) As Variant()
    ' Note: receives last column values of array two as 1-dim 1based array
    ' Purp: returns 2-dim 1-based array with row numbers if conditions met
        Dim i As Long, ii As Long, tmp()
        ReDim tmp(1 To 1, 1 To UBound(arr))     ' provide for temporary array
        For i = LBound(arr) To UBound(arr)
            If arr(i, 2) = "even" Or Right(arr(i, 5), 4) = "_tom" Then
            ' do nothing
            Else
                ii = ii + 1                     ' increment temp counter
                tmp(1, ii) = i                  ' enter row number of original column data
            End If
        Next i
        ReDim Preserve tmp(1 To 1, 1 To ii)     ' correct last dimension
        getRowNo = Application.Transpose(tmp)   ' return 2-dim array with rownumbers to be preserved
    End Function
    
    

    Example Result

    example sheet Further hint

    It's not possible to reference an array element by a .Value property, only by indices (e.g. matrix(1,1))