Define VBA array from excel range

dcase

New Member
Joined
May 10, 2009
Messages
3
Hi All,

Have put together a macro to loop through filtering a list then printing the filtered list:

Private Sub PrintAllSheets_Click()

CustNo = Array("1010", "1016", "1017", "1018")
For i = 0 To 3
Selection.AutoFilter Field:=15, Criteria1:=CustNo(i)
ExecuteExcel4Macro "PRINT(1,,,1,,,,,,,,2,,,TRUE,,FALSE)"
Next i

End Sub

Rather than defining the array manually, I would like to populate it from the following range: Sheets("Affected Customers").Range("A1:A4"). Have tried replacing Array("1010", "1016", "1017", "1018") with Array(Sheets("Affected Customers").Range("A1:A4")) but doesn't work.

Any ideas?
 

Excel Facts

Is there a shortcut key for strikethrough?
Ctrl+S is used for Save. Ctrl+5 is used for Strikethrough. Why Ctrl+5? When you use hashmarks to count |||| is 4, strike through to mean 5.
Hi

You don't need to use the Array function and variant arrays assigned from a range are always 2 dimensional - you can either deal with this in the loop, or use Application.Transpose to convert to a 1 dimensional array:

Code:
custno = Application.Transpose(Sheets("Affected Customers").Range("A1:A4").Value)
 
Upvote 0
Actually, think I need some specific guidance as it is looping through the data but only printing a page for the first criteria.
 
Upvote 0
Richard - Transpose turns a 4x1 2-D array into a 1x4 2-D array.
 
Upvote 0
Hi Jon

You might think it would work like that but it actually doesn't - it will convert a single row horizontal 2-D array into a single column 2-D array, and it will convert a single column 2-D array into a 1-D array.

You can easily check this by typing the following into the Immediate Window:

Code:
v = UBound(application.transpose([a1:a4].value),2)
'create 2-D array
?Ubound(v,1);ubound(v,2)
'returns 4   1
v = Application.Transpose(v)
?Ubound(v,1)
'returns 4
?Ubound(v,2)
'returns "Subscript out of range" ie no 2nd dimension
 
Last edited:
Upvote 0
Richard's correct, an array with the following boundaries (1 to 4, 1 to 1), will end up being (1 to 4) when called with the Transpose() function.

However, Transpose() is kind of expensive, and if you structure your iteration properly, e.g.,

http://www.mrexcel.com/forum/showpost.php?p=1931759

There's no need to do that - i.e., iterate through the 2d array.
 
Upvote 0
Here's an example:

Code:
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
    dest As Any, source As Any, ByVal bytes As Long)
 
Sub foo()
Dim varArr() As Variant
Let varArr = Range("A1:D1")
MsgBox ArrayDims(varArr)
Let varArr = WorksheetFunction.Transpose(varArr)
MsgBox ArrayDims(varArr)
Let varArr = WorksheetFunction.Transpose(varArr)
MsgBox ArrayDims(varArr)
End Sub
 
Function ArrayDims(arr As Variant) As Integer
    'http://www.vb2themax.com/Item.asp?PageID=TipBank&Cat=130&ID=27
    Dim ptr As Long
    Dim VType As Integer
 
    Const VT_BYREF = &H4000&
 
    ' get the real VarType of the argument
    ' this is similar to VarType(), but returns also the VT_BYREF bit
    CopyMemory VType, arr, 2
 
    ' exit if not an array
    If (VType And vbArray) = 0 Then Exit Function
 
    ' get the address of the SAFEARRAY descriptor
    ' this is stored in the second half of the
    ' Variant parameter that has received the array
    CopyMemory ptr, ByVal VarPtr(arr) + 8, 4
 
    ' see whether the routine was passed a Variant
    ' that contains an array, rather than directly an array
    ' in the former case ptr already points to the SA structure.
    ' Thanks to Monte Hansen for this fix
 
    If (VType And VT_BYREF) Then
        ' ptr is a pointer to a pointer
        CopyMemory ptr, ByVal ptr, 4
    End If
 
    ' get the address of the SAFEARRAY structure
    ' this is stored in the descriptor
 
    ' get the first word of the SAFEARRAY structure
    ' which holds the number of dimensions
    ' ...but first check that saAddr is non-zero, otherwise
    ' this routine bombs when the array is uninitialized
    ' (Thanks to VB2TheMax aficionado Thomas Eyde for
    '  suggesting this edit to the original routine.)
    If ptr Then
        CopyMemory ArrayDims, ByVal ptr, 2
    End If
End Function
The first MsgBox shows the Array in Row-form, the 2nd shows it in Column-form, the third shows the Column-form, with a single column, going into a 1-d array, via Transpose().

But, again, you don't need Transpose() to iterate through the array.
 
Upvote 0
I had an Immediate Window exchange before posting that comment. I don't have the trace of that any longer, and when I try to recreate it, I get a 1-D array. Hmmm.

In general, though, I don't use transpose. Manipulting the arrays in VB/VBA is quicker, and I never have this uncertainty about whether the result is one or two dimensional.
 
Upvote 0
Hello,

How does one get from a two (or greater) column set of data to a one dimension array where the values are stored in the array such that element one of the array is the top left cell of the range, the second element is the cell value below that, and the next element is the cell below that...etc, THEN go to the next colum and fill more of the array using the top cell and work down again. So by columns instead of rows. And do it efficiently? I can get it done...but I need it to be fast. For a set of data that starts in column 3, I do it like this:

Code:
Function TableToArray_StartCol3(wb As String, sht As Integer) As String()
'starts a col C1 and builds an array of single dimension that holds all strings 
 
ReDim A(1) As String
Dim rw As Long
rw = 0
Dim col As Long
col = 3
With Workbooks(wb).Sheets(sht)
    Dim c As Range
    For Each c In .Range("C1", FindLastCell(wb, sht)) 'counts left to right then next row down left to right etc.
         cnt = cnt + 1
         rw = rw + 1
         tmp = .Cells(rw, col).Value
 
         If tmp = "" Then 'check to see if cell was blank, if so reset row and col
            rw = 1
            col = col + 1
            tmp = .Cells(rw, col).Value 'get the value again
         End If
 
         If tmp <> "" Then 'if it was not blank store it
            ReDim Preserve A(cnt)
            A(cnt) = tmp
         End If
 
    Next
End With
 
TableToArray_StartCol3 = A
 
End Function 
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
 
FindLastCell(wb As String, sht As Integer) As Range
'found this online somewhere...can't remember
 
Dim theLastColumn As Integer
Dim theLastRow As Long
Dim theLastCell As Range
With Workbooks(wb).Sheets(sht)
    If WorksheetFunction.CountA(.Cells) > 0 Then
        'Search for any entry, by searching backwards by Rows.
        theLastRow = .Cells.Find(What:="*", after:=[a1], SearchOrder:=xlByRows, SearchDirection:=xlPrevious).row
        'Search for any entry, by searching backwards by Columns.
                theLastColumn = .Cells.Find(What:="*", after:=[a1], SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
                Set FindLastCell = .Range(Cells(theLastRow, theLastColumn).Address)
    End If
 
End With
End Function

Is there a faster way? Thanks!!!
 
Last edited:
Upvote 0

Forum statistics

Threads
1,214,996
Messages
6,122,636
Members
449,092
Latest member
bsb1122

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top