Reputation: 341
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
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
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