Combine data in multiple worksheets into one array

Viewed 116

I have searched for such a topic and found a UDF that combines 2d arrays into one array. I tried to loop through the worksheets like that and store the data in alll worksheets except "Search" worksheet

Sub Test()
    Dim a, temp, ws As Worksheet, m As Long
    Application.ScreenUpdating = False
        For Each ws In ThisWorkbook.Worksheets
            If ws.Name <> "Search" Then
                m = ws.Cells(Rows.Count, 1).End(xlUp).Row
                temp = ws.Range("A4:L" & m).Value
                On Error Resume Next
                'If UBound(a) > 0 Then GoTo nextP
                If a = Empty Then a = temp
                On Error GoTo 0
nextP:
                a = Combine(a, temp)
            End If
        Next ws
        
        Stop
    Application.ScreenUpdating = True
    
    'a = Range("A1:C2").Value
    'b = Range("A4:C5").Value
    'Range("F1").Resize(UBound(a, 1) * 2, UBound(a, 2)).Value = Combine(a, b)
    'Range("J1").Resize(UBound(a, 1), UBound(a, 2) * 2).Value = Combine(a, b, False)
End Sub

Function Combine(a, b, Optional f As Boolean = True)
    Dim c, lb As Long, m_A As Long, n_A As Long, m_B As Long, n_B As Long, m As Long, n As Long, i As Long, j As Long
    If TypeName(a) = "Range" Then a = a.Value
    If TypeName(b) = "Range" Then b = b.Value
    lb = LBound(a, 1)
    m_A = UBound(a, 1)
    n_A = UBound(a, 2)
    m_B = UBound(b, 1)
    n_B = UBound(b, 2)
    If f Then
        m = m_A + m_B + 1 - lb
        n = n_A
        If n_B <> n Then Combine = False: Exit Function
    Else
        m = m_A
        If m_B <> m Then Combine = False: Exit Function
        n = n_A + n_B + 1 - lb
    End If
    ReDim c(lb To m, lb To n)
    For i = lb To m
        For j = lb To n
            If f Then
                If i <= m_A Then
                    c(i, j) = a(i, j)
                Else
                    c(i, j) = b(lb + i - m_A - 1, j)
                End If
            Else
                If j <= n_A Then
                    c(i, j) = a(i, j)
                Else
                    c(i, j) = b(i, lb + j - n_A - 1)
                End If
            End If
        Next j
    Next i
    Combine = c
End Function

The code works and I got one array but the number of rows are duplicates .. Example: if the number of rows in all worksheets are 20 rows, I got an array of 40 rows .. Any idea how to fix that? Simply my request is about how to append 2d array to th main array??

3 Answers

Use an array of arrays to collect the data then iterate that to fill the single array:

Sub Test()
    Dim a, temp, ws As Worksheet, m As Long
    ReDim a(1 To ThisWorkbook.Worksheets.Count - 1)
    
    Dim x As Long
    x = 1
    
    Dim rowscnt As Long
    
    Application.ScreenUpdating = False
        For Each ws In ThisWorkbook.Worksheets
            If ws.Name <> "Search" Then
                m = ws.Cells(Rows.Count, 1).End(xlUp).Row
                a(x) = ws.Range("A4:L" & m).Value
                rowscnt = rowscnt + UBound(a(x), 1)
                x = x + 1
            End If
        Next ws
     x = 1
    ReDim temp(1 To rowscnt, 1 To 12)
    Dim i As Long
    For i = 1 To UBound(a, 1)
        Dim j As Long
        For j = 1 To UBound(a(i), 1)
            Dim k As Long
            For k = 1 To 12
                temp(x, k) = a(i)(j, k)
            Next k
            x = x + 1
        Next j
    Next i
    
    'do something with temp
    
    Application.ScreenUpdating = True
    

End Sub

Try the next adapted code, please. It will return in "A1" of "Search" sheet:

Sub TestCombine()
    Dim a, temp, ws As Worksheet, wb As Workbook, m As Long
    
    Set wb = ThisWorkbook
    For Each ws In wb.Worksheets
        If ws.name <> "Search" Then
            m = ws.cells(rows.Count, 1).End(xlUp).row
            temp = ws.Range("A4:L" & m).value
            If Not IsArray(a) Then
                a = temp
            Else
                a = combineArr(a, temp)
            End If
        End If
    Next ws
    wb.Sheets("Search").Range("A1").Resize(UBound(a), UBound(a, 2)).value = a
End Sub

Private Function combineArr(arr1, arr2)
    Dim arr3, i As Long, j As Long, k As Long
    If UBound(arr1) * UBound(arr1, 2) <= 65535 Then
        arr3 = WorksheetFunction.Transpose(arr1) 
    Else
        arr3 = transP(arr1)
    End If
    ReDim Preserve arr3(1 To UBound(arr1, 2), 1 To UBound(arr1) + UBound(arr2))
    k = UBound(arr1)
    For i = 1 To UBound(arr2)
        k = k + 1
        For j = 1 To UBound(arr2, 2)
            arr3(j, k) = arr2(i, j)
        Next j
    Next i
    If UBound(arr3) * UBound(arr3, 2) <= 65535 Then
        combineArr = WorksheetFunction.Transpose(arr3)
    Else
        combineArr = transP(arr3)
    End If
End Function

And the necessary custom transpose function:

Private Function transP(arr As Variant) As Variant 'instead of Applicaton.Transpose
    Dim trans As Variant, r As Long, C As Long
    ReDim trans(1 To UBound(arr, 2), 1 To UBound(arr))
    For r = 1 To UBound(arr)
        For C = 1 To UBound(arr, 2)
            trans(C, r) = arr(r, C)
        Next C
    Next r
    transP = trans
End Function

I have also found the following piece of code but I have not the source to be honest

Sub MyDemo()
    Dim arr, temp, ws As Worksheet, f As Boolean
    For Each ws In ThisWorkbook.Worksheets
    If ws.Name <> "Search" Then
        temp = ws.Range("A4:L" & ws.Cells(Rows.Count, 1).End(xlUp).Row).Value
        If f Then
            arr = ArrayJoin(arr, temp)
        Else
            arr = temp
            f = True
        End If
        End If
    Next ws
    Sheets("Search").Range("A100").Resize(UBound(arr, 1), UBound(arr, 2)).Value = arr
End Sub

Function ArrayJoin(ByVal a, ByVal b)
    Dim i As Long, ii As Long, ub As Long
    ub = UBound(a, 1)
    a = Application.Transpose(a)
    ReDim Preserve a(1 To UBound(a, 1), 1 To ub + UBound(b, 1))
    a = Application.Transpose(a)
    For i = LBound(b, 1) To UBound(b, 1)
        For ii = 1 To UBound(b, 2)
            a(ub + i, ii) = b(i, ii)
        Next ii
    Next i
    ArrayJoin = a
End Function
Related