xyz
xyz

Reputation: 2300

Get a filtered range into an array

I am trying to get a filtered range into an array, on my test data the array fArr has the proper dim and fLR is the proper count of the filter range

But filRange is always only the header range NOT the filtered range

How to get filRange to be the filtered range?

Or to the point how to get fArr to be an array of the filter data?

Thanks

Sub arrFilterdRng()
Dim fArr As Variant
Dim rRange As Range, filRange As Range, myCell As Range
Dim fLR As Long, rCtr As Long

'Remove any filters
ActiveSheet.AutoFilterMode = False

'~~> Set your range
Set rRange = Sheets("Z").UsedRange

With rRange
    '~~> Set your criteria and filter
    .AutoFilter Field:=3, Criteria1:="*"

    Set filRange = .SpecialCells(xlCellTypeVisible).EntireRow
    fLR = .Resize(, 1).SpecialCells(xlCellTypeVisible).Count
    Debug.Print fLR
    
    ReDim fArr(1 To fLR, 1 To .Columns.Count)
    Debug.Print UBound(fArr, 1), UBound(fArr, 2)
    
    rCtr = 0
    For Each myCell In filRange.Columns(1)
      rCtr = rCtr + 1
       For cCtr = 1 To .Columns.Count
         fArr(rCtr, cCtr) = myCell.Offset(0, cCtr - 1).value
       Next cCtr
   Next myCell
End With

'Remove any filters
ActiveSheet.AutoFilterMode = False

End Sub

My data looks like this (all text)

enter image description here

Upvotes: 1

Views: 7543

Answers (2)

Ambie
Ambie

Reputation: 4977

My feeling is that the wildcard in your criteria is causing the trouble.

"*" only works for strings, so if your data are numbers (including dates) then they would be removed by the filter (ie they wouldn't be visible), so you would indeed only have the header in your range.

If you want numerical values, then one way of doing it would be to define a value, say:

.AutoFilter Field:=3, Criteria1:=">0"

or, if you want limits:

.AutoFilter Field:=3, Criteria1:=">0", Operator:=xlAnd, Criteria2:="<10"

If, on the other hand, you just want anything but blank cells, then the syntax should be:

.AutoFilter Field:=3, Criteria1:="<>"

You should also be aware that if the filtered range contains non-contiguous ranges, then each 'separate' range would be contained within the Areas collection. This means something like filRange.Rows.Count would only return the row count of the first area; and you can get real difficulties when you try to Offset and/or Resize the filtered range. It's also not possible to directly read non-contiguous ranges into an array using the .Value property.

I'm not sure your code is the most efficient way of handling your task, but keeping the same structure it could look like this:

Dim rRange As Range, filRange As Range
Dim myArea As Range, myRow As Range, myCell As Range
Dim fArr() As Variant
Dim r As Long

With ThisWorkbook.Worksheets("Z")
    .AutoFilterMode = False
    Set rRange = .UsedRange
End With

With rRange
    .AutoFilter Field:=3, Criteria1:=">0"
    Set filRange = .SpecialCells(xlCellTypeVisible)
End With

With filRange
    r = -1 'start at -1 to remove heading row
    For Each myArea In filRange.Areas
        r = r + myArea.Rows.Count
    Next
    ReDim fArr(1 To r, 1 To .Columns.Count)
End With

r = 1
For Each myArea In filRange.Areas
    For Each myRow In myArea.Rows
        If myRow.Row <> 1 Then
            For Each myCell In myRow.Cells
                fArr(r, myCell.Column) = myCell.Value
            Next
            r = r + 1
        End If
    Next
Next

Upvotes: 2

Robin Mackenzie
Robin Mackenzie

Reputation: 19319

Perhaps your data has more complexity, but you can simply assign the values of a range to an array with:

var = rng.SpecialCells(xlCellTypeVisible).Value

Thus no need to loop over the data.

Here's a working example with this simple grid of data:

enter image description here

This code:

Option Explicit

Sub arrFilterdRng()

    Dim ws As Worksheet '<-- your worksheet
    Dim rng As Range    '<-- your range to filter
    Dim var As Variant  '<-- will hold array of visible data
    Dim lng1 As Long, lng2 As Long

    ' get sheet; remove filters
    Set ws = ThisWorkbook.Worksheets("Sheet2")
    ws.AutoFilterMode = False

    ' get range; apply filter
    Set rng = ws.UsedRange
    rng.AutoFilter Field:=1, Criteria1:="x"

    ' assign visible range to array
    var = rng.SpecialCells(xlCellTypeVisible).Value

    ' test array
    For lng1 = LBound(var, 1) To UBound(var, 1)
        For lng2 = LBound(var, 2) To UBound(var, 2)
            Debug.Print var(lng1, lng2)
        Next lng2
    Next lng1

End Sub

Results in this on the sheet:

enter image description here

And the output to the Immediate window for the content of var is:

a
b
c
x
 2 
 3 
x
 5 
 6 

Upvotes: 0

Related Questions