MrPatterns
MrPatterns

Reputation: 4434

How do I copy a filtered range into an array? (Excel VBA)

I use this formula to copy unique records from Column A into Column B.

Range("A1", Range("A100").End(xlUp)).AdvancedFilter Action:=xlFilterCopy, CopyToRange:=Range("B1"), Unique:=True

Instead of copying it into Column B how do you put the filtered results into an array in Excel VBA?

Upvotes: 7

Views: 46837

Answers (7)

Charlio
Charlio

Reputation: 386

Here's another way to do it. If there are no results it just does nothing.

Public Sub filteredRangeToArray(rg As Range, arr As Variant)

Dim i As Long
Dim j As Long
Dim row As Range
'If 0 results in Filter just exit
If Not rg.SpecialCells(xlCellTypeVisible).Count > 0 Then Exit Sub
i = 1
Erase arr
ReDim arr(1 To rg.Columns.Count, 1 To _
   rg.Columns(1).SpecialCells(xlCellTypeVisible).Count)
For Each row In rg.Rows
 If Not row.Hidden Then
  For j = LBound(arr, 1) To UBound(arr, 1)
  arr(j, i) = row.Cells(j)
  Next j
  i = i + 1
 End If
Next row
arr = WorksheetFunction.Transpose(arr)
End Sub

Upvotes: 2

Ibo
Ibo

Reputation: 4309

A simple way to store a filtered range in an array is to use the copy-paste trick. Create a worksheet and make it hidden or very hidden. Say its code name is sht_calc. This function will give you a 2D array unless you only have one column and the filtered rows are only one, which in that case it will be a simple variant variable and not an array

Function GetArrayFromFilteredRange(rng As Range) As Variant
    Dim arr As Variant
    
    sht_calc.Cells.Clear
    rng.Copy sht_calc.Range("A1")
    arr = sht_calc.UsedRange.Value
    
    GetArrayFromFilteredRange = arr
End Function

For example if you want to get the array of filtered rows in a table called Table1 in a worksheet with a code name of sht1 you can simply do this:

dim rng as range
arr = GetArrayFromFilteredRange(sht1.ListObjects("Table1").DataBodyRange.SpecialCells(xlCellTypeVisible))

arr=GetArrayFromFilteredRange(rng)

Upvotes: 1

mmurrietta
mmurrietta

Reputation: 191

Just in case anyone ever looks at this again... I created this function to work on a 1-D range but it will also write a higher dimension range to a 1-D array; it shouldn't be too hard to modify to write a multiple dimension range to a "same shape" array. You need to have a reference to scrrun.dll to create the dictionary object. Scaling may be a problem since a "for each" loop is used but if you are using EXCEL this is likely nothing you are worried about:

Function RangeToArrUnique(rng As Range)
    Dim d As Object, cl As Range
    Set d = CreateObject("Scripting.Dictionary")
    For Each cl In rng
        d(cl.Value) = 1
    Next cl
    RangeToArrUnique = d.keys
End Function

I've tested this in this way:

Dim dat as worksheet
set dat = sheets("Data")
roomArr = Array("OR01","OR02","OR03")
dat.UsedRange.AutoFilter field:=2, criteria1:=roomArr, operator:=xlFilterValues
fltArr = RangeToArrUnique(dat.UsedRange.SpecialCells(CellTypeVisible))

Hope this helps someone out there!

Upvotes: 4

Johan G
Johan G

Reputation: 427

It has been exactly a year since this question was asked but I ran into the same problem today and here is my solution for it:

Function copyFilteredData() As Variant
    Dim selectedData() As Variant
    Dim aCnt As Long
    Dim rCnt As Long

    Range("A1").CurrentRegion.SpecialCells(xlCellTypeVisible).Select
    On Error GoTo MakeArray:
    For aCnt = 1 To Selection.Areas.Count
        For rCnt = 1 To Selection.Areas(aCnt).Rows.Count
            ReDim Preserve SelectedData(UBound(selectedData) + 1)
            selectedData(UBound(selectedData)) = Selection.Areas(aCnt).Rows(rCnt)
        Next
    Next

    copyFilteredData = selectedData
    Exit Function

MakeArray:
    ReDim selectedData(1)
    Resume Next

End Function 

This will leave element 0 of the array empty but UBound(SelectedData) returns the number of rows in the selection

Upvotes: 6

Sorceri
Sorceri

Reputation: 8033

You will want to Read this and it will point you in the right direction

It says:

  1. Use the AdvancedFilter method to create the filtered range in some unused area of a worksheet
  2. Assign the Value property of that range to a Variant to create a two-dimensional array
  3. Use the ClearContents method of that range to get rid of it

Upvotes: 1

Tim Williams
Tim Williams

Reputation: 166256

Sub tester()

    Dim arr
    arr = UniquesFromRange(ActiveSheet.Range("A1:A5"))
    If UBound(arr) = -1 Then
        Debug.Print "no values found"
    Else
        Debug.Print "got array of unique values"
    End If

End Sub


Function UniquesFromRange(rng As Range)
    Dim d As Object, c As Range, tmp
    Set d = CreateObject("scripting.dictionary")
    For Each c In rng.Cells
       tmp = Trim(c.Value)
       If Len(tmp) > 0 Then
            If Not d.Exists(tmp) Then d.Add tmp, 1
       End If
    Next c
    UniquesFromRange = d.keys
End Function

Upvotes: 2

enderland
enderland

Reputation: 14135

The following takes information from column A and gives a list. It assumes you have a "Sheet3" which is available for data input (you may wish to change this).

Sub test()

    Dim targetRng As Range
    Dim i As Integer

    Set targetRng = Sheets(3).Range("a1")
    Range("A1", Range("A999").End(xlUp)).AdvancedFilter Action:=xlFilterCopy, CopyToRange:=targetRng, Unique:=True

    Dim numbElements As Integer
    numbElements = targetRng.End(xlDown).Row
    Dim arr() As String

    ReDim arr(1 To numbElements) As String

    For i = 1 To numbElements
        arr(i) = targetRng.Offset(i - 1, 0).Value
    Next i

End Sub

Upvotes: 0

Related Questions