1

I've read some posts saying that you can only reDim the last dimention of a multi-dimensional array in VBA.

Is there any work around for such a case?

Sub test()
    Dim arr As Variant
    Dim i As Long
    Dim j As Long
        
    For i = 1 To 10
        For j = 1 To 10
            ReDim Preserve arr(1 To i, 1 To j)
            arr(i, j) = i
        Next j
    Next i
End Sub

For a spreadsheet, the 1st dimension of 2D array is row, and the 2nd dimesion is column.

Isn't it a very commond case to be in-need to add either a row or a column into the data we are working with?


Some more explanation:

My project requires to load like 10 workbooks, and each wb has an unknown number of sheets with unknown rows of Data.

I am trying to load all of them, put them all into one 2D array since they share the same structure, added some columns ahead of each row according to which doc and sheet they came from.

That is why I have to reDim both dimensions.

VBasic2008
  • 44,888
  • 5
  • 17
  • 28
Ping
  • 891
  • 1
  • 2
  • 10
  • As I understand it it's only `ReDim Preserve`. The workaround is to read the data into some other structure, create a new empty array with required dimensions, then read the data back in. Are you certain you need to redim both dimensions? – Nick.Mc Jan 08 '23 at 02:00
  • this is just a sample, in the real situation, the upper limit of both dimesions are unknown to me. – Ping Jan 08 '23 at 02:00
  • Not as common as you might think. You do have worksheets full of rows and columns if you need them. In any event, you work within the limitations of the language, so that's that. – topsail Jan 08 '23 at 02:01
  • _Isn't it a very common case to be in-need to add either a row or a column into the data we are working with?_ I'm going to straight out say it: If you are working a lot with data, VBA is not the tool you should be using Python seems to be the language if choice nowadays. – Nick.Mc Jan 08 '23 at 02:03
  • My project requires to load like 10 workbooks and each have unknown number of sheets with unknown rows of Data, I am trying to load all of them and put them all into one 2D array, with some added columns according to which doc and sheet they come from. That is why I have to ```reDim``` both dimensions. – Ping Jan 08 '23 at 02:03
  • I suggest either don't load then into an array, load them into another excel sheet. _or_ load all the files upfront and dimension your array upfront before loading data. – Nick.Mc Jan 08 '23 at 02:04
  • Regardless I suggest explaining what you're trying to do because there will likely be better ways of doing it. – Nick.Mc Jan 08 '23 at 02:05
  • 1
    Also found this where someone wrote a function to redim preserve as you wish. However I think there is probably a better way to go about this. https://stackoverflow.com/questions/13183775/excel-vba-how-to-redim-a-2d-array – Nick.Mc Jan 08 '23 at 02:07
  • I'm thinking of using some other language like Javascript to work with the 2D arrays and return the result back into VBA after processing. As I can remember, there should be official library which support planting some javascript into a VBA project...? – Ping Jan 08 '23 at 02:15
  • Why do you need all this data in an array? A common case would be to copy all the data to a worksheet when you would open, copy and close as many times as there are worksheets. If you need the data in a single 2D array, you could simply create a collection and write all the arrays containing the data to it. Then you could dimension a resulting array according to the sizes of the arrays (rows) which you have summed up while copying to the collection and copy the data from the arrays in the collection to the resulting array. Share the code that loops and references each range to see how. – VBasic2008 Jan 08 '23 at 03:08
  • @VBasic2008 It is an issue happens while trying to adept a new language. In my previous working environment, I used to process data within 2D arrays and only output the data to spreadsheet with the final result, because it is very time / resouces comsuming to call any spreadsheet service. Actually I don't think it have to be done with 2D Array at all, that's why I'm looking for a work around. Thanks for all the suggestions, I'll try them out to see if any could fit my case. – Ping Jan 08 '23 at 04:41
  • Don't complicate it by introducing javascript. Is there any reason you can't pre load all data, work out the dimensions up front so you don't need to `redim preserve`? _they share the same structure, added some columns_ so when you load the first sheet, you should know how many columns you need and this won't change. Only the rows will change. – Nick.Mc Jan 08 '23 at 10:35
  • Redim work only one time, first count, on finish loop apply your redim. Only one time redim work. duplicata your loop one only tô count set you redim, Second loop tô insert values – Julio Gadioli Soares Jan 08 '23 at 12:19
  • Preserve is good If call another sub or funcion, If not do this not os need preserve. Only one time redim work – Julio Gadioli Soares Jan 08 '23 at 12:22
  • @Nick.McDermaid As you said, I only need to change the rows count, but row is defined by the 1st dimension which I can’t change. – Ping Jan 08 '23 at 15:54
  • Then make it the second dimension??? The first dimension can be known fixed columns – Nick.Mc Jan 09 '23 at 05:39

2 Answers2

0

For simplicity, the following code only combines the data from each worksheet in the active workbook. However, it can be amended to include other workbooks as well.

The code loops through each worksheet in the active workbook. For each worksheet, it loops through each row, excluding the header row. For each row, the data is first transferred to an array, and then added to a collection. Then the combined data from the collection is transferred to another array. And, lastly, the contents of the array is transferred to a newly created worksheet.

Again, for simplicity, I have assumed that the data for each sheet contains only two columns. So I have declared currentRow() as a 1-Row by 4-Column array. The first two columns will store the worksheet data, and the third and fourth columns will store the corresponding workbook name and sheet name. You'll need to change the second dimension accordingly.

Option Explicit

Sub CombineAllData()

    Dim sourceWorkbook As Workbook
    Dim currentWorksheet As Worksheet
    Dim newWorksheet As Worksheet
    Dim currentData() As Variant
    Dim currentRow(1 To 1, 1 To 4) As Variant
    Dim allData() As Variant
    Dim col As Collection
    Dim itm As Variant
    Dim i As Long
    Dim j As Long
    
    Set col = New Collection
    
    Set sourceWorkbook = ActiveWorkbook
    
    For Each currentWorksheet In sourceWorkbook.Worksheets
    
        'get the data from the current worksheet
        currentData = currentWorksheet.Range("a1").CurrentRegion.Value
        
        'add each row of data to the collection, excluding the header row
        For i = LBound(currentData) + 1 To UBound(currentData)
            For j = 1 To 2
                currentRow(1, j) = currentData(i, j)
            Next j
            currentRow(1, 3) = sourceWorkbook.Name
            currentRow(1, 4) = currentWorksheet.Name
            col.Add currentRow
        Next i
        
    Next currentWorksheet
    
    'resize the array to store the combined data
    ReDim allData(1 To col.Count, 1 To 4)
    
    'transfer the data from the collection to the array
    With col
        For i = 1 To .Count
            For j = 1 To 4
                allData(i, j) = .Item(i)(1, j)
            Next j
        Next i
    End With
    
    'add a new worksheet to the workbook
    Set newWorksheet = Worksheets.Add
    
    'transfer the contents of the array to the new worksheet
    newWorksheet.Range("a1").Resize(UBound(allData), UBound(allData, 2)).Value = allData
    
End Sub
Domenic
  • 7,844
  • 2
  • 9
  • 17
0

Stack Ranges

  • For simplicity, it is assumed that the data starts with cell A1, that it is in table format (one row of headers, no empty rows or columns) and the data ranges have at least two cells.
  • Also, it is assumed that the folder contains nothing but the source files.
Sub StackRanges()

    Const sFolderPath As String = "C:\Test\"
    
    Dim fso As Object: Set fso = CreateObject("Scripting.FileSystemObject")
    Dim scoll As Collection: Set scoll = New Collection
    
    Application.ScreenUpdating = False
    
    Dim fsoFile As Object, swb As Workbook, sws As Worksheet
    Dim srCount As Long, scCount As Long, drCount As Long, dcCount As Long
    
    For Each fsoFile In fso.GetFolder(sFolderPath).Files
        Set swb = Workbooks.Open(fsoFile.Path, True, True)
        For Each sws In swb.Worksheets
            With sws.Range("A1").CurrentRegion
                srCount = .Rows.Count - 1 ' lose the header
                If srCount > 0 Then
                    scoll.Add .Resize(srCount).Offset(1).Value
                    drCount = drCount + srCount ' total
                    scCount = .Columns.Count
                    If scCount > dcCount Then dcCount = scCount ' max
                End If
            End With
        Next sws
        swb.Close SaveChanges:=False
    Next fsoFile
    
    If scoll.Count = 0 Then Exit Sub

    Dim dData(): ReDim dData(1 To drCount, 1 To dcCount)
     
    Dim sItem, sr As Long, dr As Long, c As Long
    
    For Each sItem In scoll
        For sr = 1 To UBound(sItem, 1)
            dr = dr + 1
            For c = 1 To UBound(sItem, 2)
                dData(dr, c) = sItem(sr, c)
            Next c
        Next sr
    Next sItem

    ' Write the values from the array to a new single-worksheet workbook.
'    With Workbooks.Add(xlWBATWorksheet)
'        .Worksheets(1).Range("A2").Resize(drCount, dcCount).Value = dData
'        .Saved = True ' to close without confirmation
'    End With

    Application.ScreenUpdating = True
    
    MsgBox "Ranges stacked.", vbInformation

End Sub
VBasic2008
  • 44,888
  • 5
  • 17
  • 28