Bendaua
Bendaua

Reputation: 341

Filter Array in Excel VBA

How can I filter a multidimensional array?

My code does neither work nor does it seem neat:

Option Explicit
Sub CalcE()
Dim TotalRows As Long
Dim myArray, myArray2 As Variant
Dim i, a As Integer

Populate Array

TotalRows = Sheets("Data").Rows(Rows.Count).End(xlUp).Row
myArray = Sheets("Data").Range("A5:F" & TotalRows)
MsgBox "Array populated with " & UBound(myArray) & "entries."

Filter myArray entries into myArray2, but only the column 1, 4 and 6.

a = 0
For i = 0 To UBound(myArray)
    If myArray(i, 1) > 1 Then
        myArray2(a, 1) = myArray(i, 1)
        myArray2(a, 2) = myArray(i, 4)
        myArray2(a, 3) = myArray(i, 6)
        a = a + 1
    End If
Next i    
MsgBox "Array populated now with " & UBound(myArray2) & "entries."
End Sub

I googled and figured that arrays in Excel seem to be very inflexible things, not nice to work with. People usually give up on VBA Arrays and use AutoFilter methods instead. I wounder whether there really isn't a good way. It would be so neat to have!

Upvotes: 0

Views: 14430

Answers (2)

Subodh Tiwari sktneer
Subodh Tiwari sktneer

Reputation: 9966

If all you need is to store the columns 1, 4 and 6 into myArray2, give this a try...

Dim ws As Worksheet
Set ws = Sheets("Data")
TotalRows = ws.Rows(Rows.Count).End(xlUp).Row
myArray2 = Application.Index(ws.Cells, Evaluate("Row(5:" & TotalRows & ")"), Array(1, 4, 6))

Or you may tweak your code like this...

Dim ws As Worksheet
Set ws = Sheets("Data")
Dim cnt As Long, j As Long
TotalRows = ws.Rows(Rows.Count).End(xlUp).Row
myArray = ws.Range("A5:F" & TotalRows).Value
cnt = Application.CountIf(ws.Range("A5:A" & TotalRows), ">1")
If cnt = 0 Then Exit Sub
ReDim myArray2(1 To cnt, 1 To 3)
For i = 1 To UBound(myArray, 1)
    If myArray(i, 1) > 1 Then
        j = j + 1
        myArray2(j, 1) = myArray(i, 1)
        myArray2(j, 2) = myArray(i, 4)
        myArray2(j, 3) = myArray(i, 6)
    End If
Next i

MsgBox UBound(myArray2, 1)

Upvotes: 3

to StackOverflow
to StackOverflow

Reputation: 124696

Arrays are not very flexible: in particular not easy to resize (though you can do so using Redim Preserve.

Personally I would use a Collection if you want a variable number of items and or want to filter items in VBA.

First define a Class Module with properties or fields that represent the columns of your 2D array. You should give the class and it's properties meaningful names, and appropriate data types, but I don't know your application so I'll use:

Class Module "MyClass":

    Public Col1 As Variant
    Public Col4 As Variant
    Public Col6 As Variant

You can then create a Collection and add instances of your class to it as follows:

Dim col As Collection
Set col = New Collection
For i = LBound(myArray, 1) To UBound(myArray, 1)
    If myArray(i, 1) > 1 Then
        Dim c As MyClass
        Set c = New MyClass
        c.Col1 = myArray(i, 1)
        c.Col4 = myArray(i, 4)
        c.Col6 = myArray(i, 6)
        col.Add c
    End If
Next I

You can then filter it further, e.g.:

Dim col2 As Collection
Set col2 = New Collection
For Each c In col
    If c.Col1 = 5 Then
        col2.Add c
    End If
Next c

And finally copy it back to a 2D array so you can write it back to an Excel Sheet:

Dim myArray2() As Variant
Dim c As MyClass
ReDim myArray2(0 To col2.Count - 1, 0 To 6)
For i = 0 To col2.Count - 1
    Set c = col2(i + 1) ' Collection indexes are 1-based
    myArray2(i, 1) = c.Col1
    myArray2(i, 4) = c.Col4
    myArray2(i, 6) = c.Col6
Next i

You could even write a Class Module that is a strongly-typed collection of MyClass objects, a class module MyClassCollection as described in the linked blog article.

Upvotes: 1

Related Questions