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?
 
mountainclimber11

Is this connected to your other thread where you said you had code that was taking a week to run?

Perhaps if you explained what you are ultimately trying to achieve, perhaps even post some sample data, someone can make some suggestions on optimization.:)
 
Upvote 0

Excel Facts

How can you turn a range sideways?
Copy the range. Select a blank cell. Right-click, Paste Special, then choose Transpose.
Well, thats cheating Tusharm! :)
Yours is fastest by a long shot. That is awesome and I've never seen that in VBA before...good to know. But you are ACCESSING the value not building the array.

Although you void building the 1-d array, which saves time, my main concern is the time it takes to ACCESS the values. Your method of accessing the values take longer because of the calc's in the properties. I explained a few posts ago that I access this array millions of times, but I only build the array a few thousand times. So the real time saver will be in mimizing access time using a 1-d array. However to do this, I do need to build the 1-d from my table of values so I can access the values very fast later. Hope that makes sense. That Properties thing reminds me of C++...didn't know you could do it in VBA.

Anyway, if there is an faster way to build a 1-d array from data that looks like this in Excel (such that the 1-d array elements look like this a,b,c,d,e), please post: (for the fastest method so far see the code at the bottom of this post...it uses data that starts in column 3)

a d
b e
c

Norie - I spent an hour composing a really long post in that other thread detailing the entire process (at your request). I don't know what more I need to do. The data is all accessed from different excel workbooks so I use With blocks a lot. Its too complex to explain more I think. So I am asking specific questions.

Code:
Function TableToArray(wb As String, sht As Integer) As String()
With Workbooks(wb).Sheets(sht)
    Dim d2Array As Variant
    d2Array = .Range("C1", FindLastCell())
    ReDim d1Array(Application.CountA(.Cells)) As String
    'MsgBox UBound(d1Array)
    Dim idx As Integer
    'MsgBox LastRowInOneColumn(3, wb, sht) & " rows"
    For j = 1 To Application.CountA(.Columns)
        For k = 1 To LastRowInOneColumn(3, wb, sht)
        idx = idx + 1
        If d2Array(k, j) = "" Then
            GoTo done
        End If
        d1Array(idx) = d2Array(k, j)
        'MsgBox idx & " =idx k= " & k & " j= " & j
        Next k
    Next j
done:
End With
TableToArray = d1Array
End Function
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function LastRowInOneColumn(xcol As Long, wb As String, sht As Integer) As Long
'Find the last used row in a Column: column A in this example
    Dim xLastRow As Long
    With Workbooks(wb).Sheets(sht)
        xLastRow = .Cells(.Rows.count, xcol).End(xlUp).row
    End With
 
LastRowInOneColumn = xLastRow
End Function
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function FindLastCell() As Range
Dim theLastColumn As Integer
Dim theLastRow As Long
Dim theLastCell As Range
With ActiveSheet
    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
 
Upvote 0
Sorry, I might have missed that post.:oops:

I've just had a look back at the thread and can see you have posted some sort of explanation.

The thing that might be missing is an explanation of what you are actually trying to achieve.

Seeing some sample data and expected results might also help.:)
 
Upvote 0
<font face=Courier New><SPAN style="color:#007F00">'************Must be in Standard Module********************</SPAN><br><SPAN style="color:#00007F">Type</SPAN> LcelCcnt<br>Lcel <SPAN style="color:#00007F">As</SPAN> Range<br>Ccnt <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN><br><SPAN style="color:#00007F">End</SPAN> <SPAN style="color:#00007F">Type</SPAN><br><SPAN style="color:#007F00">'************End Contents Standard Module*******************</SPAN><br><SPAN style="color:#00007F">Function</SPAN> TableToArray2(wb <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">String</SPAN>, sht <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Integer</SPAN>) <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">String</SPAN>()<br><SPAN style="color:#00007F">Dim</SPAN> myLastCell <SPAN style="color:#00007F">As</SPAN> Range<br><SPAN style="color:#00007F">Dim</SPAN> myCellsCount <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN><br><SPAN style="color:#00007F">Dim</SPAN> myReturn <SPAN style="color:#00007F">As</SPAN> LcelCcnt<br>myReturn = FindLastCell_V2<br>myLastCell = myReturn.Lcel<br>myCellsCount = myReturn.Ccnt<br><br><SPAN style="color:#00007F">With</SPAN> Workbooks(wb).Sheets(sht)<br>    <SPAN style="color:#00007F">Dim</SPAN> d2Array <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Variant</SPAN><br>    d2Array = .Range("C1", myLastCell)<br>    <SPAN style="color:#00007F">ReDim</SPAN> d1Array(myCellsCount) <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">String</SPAN><br>    <SPAN style="color:#007F00">'MsgBox UBound(d1Array)</SPAN><br>    <SPAN style="color:#00007F">Dim</SPAN> idx <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Integer</SPAN><br>    <SPAN style="color:#007F00">'MsgBox LastRowInOneColumn(3, wb, sht) & " rows"</SPAN><br>    <SPAN style="color:#00007F">For</SPAN> j = 1 <SPAN style="color:#00007F">To</SPAN> Application.CountA(.Columns) <SPAN style="color:#007F00">'Add this one to Type LcelCcnt</SPAN><br>        <SPAN style="color:#00007F">For</SPAN> k = 1 <SPAN style="color:#00007F">To</SPAN> LastRowInOneColumn(3, wb, sht)<br>        idx = idx + 1<br>        <SPAN style="color:#00007F">If</SPAN> d2Array(k, j) = "" <SPAN style="color:#00007F">Then</SPAN><br>            <SPAN style="color:#00007F">GoTo</SPAN> done<br>        <SPAN style="color:#00007F">End</SPAN> <SPAN style="color:#00007F">If</SPAN><br>        d1Array(idx) = d2Array(k, j)<br>        <SPAN style="color:#007F00">'MsgBox idx & " =idx k= " & k & " j= " & j</SPAN><br>        <SPAN style="color:#00007F">Next</SPAN> k<br>    <SPAN style="color:#00007F">Next</SPAN> j<br>done:<br><SPAN style="color:#00007F">End</SPAN> <SPAN style="color:#00007F">With</SPAN><br>TableToArray2 = d1Array<br><SPAN style="color:#00007F">End</SPAN> <SPAN style="color:#00007F">Function</SPAN><br><SPAN style="color:#007F00">''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''</SPAN><br><br><SPAN style="color:#00007F">Sub</SPAN> Test_FindlastCell()<br><SPAN style="color:#00007F">Dim</SPAN> TestVar1 <SPAN style="color:#00007F">As</SPAN> LcelCcnt<br><SPAN style="color:#00007F">Dim</SPAN> TestVar2 <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">String</SPAN><br><SPAN style="color:#00007F">Dim</SPAN> TestVar3 <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN><br>   <br>TestVar1 = FindLastCell_V2<br>TestVar2 = TestVar1.Lcel.Address<br>TestVar3 = TestVar1.Ccnt<br><SPAN style="color:#00007F">End</SPAN> <SPAN style="color:#00007F">Sub</SPAN><br><br><SPAN style="color:#00007F">Function</SPAN> FindLastCell_V2() <SPAN style="color:#00007F">As</SPAN> LcelCcnt<br><SPAN style="color:#00007F">Dim</SPAN> theLastColumn <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Integer</SPAN><br><SPAN style="color:#00007F">Dim</SPAN> theLastRow <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN><br><SPAN style="color:#00007F">Dim</SPAN> theLastCell <SPAN style="color:#00007F">As</SPAN> Range<br><SPAN style="color:#00007F">With</SPAN> ActiveSheet<br>   <SPAN style="color:#007F00">'Check for empty sheet</SPAN><br>   <SPAN style="color:#00007F">If</SPAN> WorksheetFunction.CountA(Cells) = 0 <SPAN style="color:#00007F">Then</SPAN> <SPAN style="color:#00007F">GoTo</SPAN> OOPS<br>   <SPAN style="color:#007F00">'Search for any entry, by searching backwards by Rows.</SPAN><br>   theLastRow = .Cells.Find(What:="*", after:=[a1], SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row<br>   <SPAN style="color:#007F00">'Search for any entry, by searching backwards by Columns.</SPAN><br>      theLastColumn = .Cells.Find(What:="*", after:=[a1], SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column<br>      <SPAN style="color:#00007F">Set</SPAN> FindLastCell_V2.Lcel = .Range(Cells(theLastRow, theLastColumn).Address)<br>      FindLastCell_V2.Ccnt = theLastColumn<br><SPAN style="color:#00007F">End</SPAN> <SPAN style="color:#00007F">With</SPAN><br>OOPS: <SPAN style="color:#007F00">'Error msgbox here</SPAN><br><SPAN style="color:#00007F">End</SPAN> <SPAN style="color:#00007F">Function</SPAN><br> </FONT>
 
Upvote 0
Unless there is reason to be believe that the speed of the calculation in the 'data abstraction layer' * millions > speed of reorganizing the data * thousands, I would go with the easier approach, i.e., the DAL.

Well, thats cheating Tusharm! :)
Yours is fastest by a long shot. That is awesome and I've never seen that in VBA before...good to know. But you are ACCESSING the value not building the array.

Although you void building the 1-d array, which saves time, my main concern is the time it takes to ACCESS the values. Your method of accessing the values take longer because of the calc's in the properties. I explained a few posts ago that I access this array millions of times, but I only build the array a few thousand times. So the real time saver will be in mimizing access time using a 1-d array. However to do this, I do need to build the 1-d from my table of values so I can access the values very fast later. Hope that makes sense. That Properties thing reminds me of C++...didn't know you could do it in VBA.

Anyway, if there is an faster way to build a 1-d array from data that looks like this in Excel (such that the 1-d array elements look like this a,b,c,d,e), please post: (for the fastest method so far see the code at the bottom of this post...it uses data that starts in column 3)

a d
b e
c

Norie - I spent an hour composing a really long post in that other thread detailing the entire process (at your request). I don't know what more I need to do. The data is all accessed from different excel workbooks so I use With blocks a lot. Its too complex to explain more I think. So I am asking specific questions.

Code:
Function TableToArray(wb As String, sht As Integer) As String()
With Workbooks(wb).Sheets(sht)
    Dim d2Array As Variant
    d2Array = .Range("C1", FindLastCell())
    ReDim d1Array(Application.CountA(.Cells)) As String
    'MsgBox UBound(d1Array)
    Dim idx As Integer
    'MsgBox LastRowInOneColumn(3, wb, sht) & " rows"
    For j = 1 To Application.CountA(.Columns)
        For k = 1 To LastRowInOneColumn(3, wb, sht)
        idx = idx + 1
        If d2Array(k, j) = "" Then
            GoTo done
        End If
        d1Array(idx) = d2Array(k, j)
        'MsgBox idx & " =idx k= " & k & " j= " & j
        Next k
    Next j
done:
End With
TableToArray = d1Array
End Function
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function LastRowInOneColumn(xcol As Long, wb As String, sht As Integer) As Long
'Find the last used row in a Column: column A in this example
    Dim xLastRow As Long
    With Workbooks(wb).Sheets(sht)
        xLastRow = .Cells(.Rows.count, xcol).End(xlUp).row
    End With
 
LastRowInOneColumn = xLastRow
End Function
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function FindLastCell() As Range
Dim theLastColumn As Integer
Dim theLastRow As Long
Dim theLastCell As Range
With ActiveSheet
    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
 
Upvote 0
Even faster might be to write a "data abstraction layer." And, this would be a great place to use a Property in a standard module!

For more on the subject of properties in a standard module see
Case Study – Property procedures in a standard module
http://www.tushar-mehta.com/publish_train/xl_vba_cases/vba-property_procs_in_std_module.htm

Back to your problem...for my test I had data in A1:B20.
Code:
Option Explicit

Dim C As Integer, R As Long
Dim Arr
Sub Initialize(Cell1 As Range)
    Arr = Cell1.CurrentRegion.Value
    C = UBound(Arr, 2)
    R = UBound(Arr)
    End Sub

Property Get MyArr(I)
    MyArr = Arr((I - 1) Mod R + 1, ((I - 1) \ R) + 1)
    End Property
Property Let MyArr(I, uVal)
    Arr((I - 1) Mod R + 1, ((I - 1) \ R) + 1) = uVal
    End Property

Sub testProps()
    Initialize Cells(1, 1)
    MsgBox MyArr(1) & "," & MyArr(10) & "," & MyArr(11) & "," & MyArr(20)
    MyArr(11) = 11
    MsgBox MyArr(11)
    End Sub

Very nice Tushar (y)
 
Upvote 0
my main concern is the time it takes to ACCESS the values.

To shrink the redimming time

Pseudocode:
Code:
Dim array(2 As Double?, 1,000,000)
 
When add values to array then
array(1 1) = array(1, 1) + 1
 
After add values then
If array(1, 1) = 1,000,000 Then
redim preserve array(2,000,000)
I know, redim only redims the last dimension...
 
Last edited:
Upvote 0

Forum statistics

Threads
1,215,497
Messages
6,125,158
Members
449,208
Latest member
emmac

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