Transpose関数を作ることにした

先日、Transpose関数の限界を知った。
infoment.hatenablog.com

仕方ない、自分で作るか。
f:id:Infoment:20200829164345p:plain

今回はこちらに倣って、全てではないが、多くを日本語で書いてみた。
www.limecode.jp

Function UDF_Transpose(ByVal 元配列 As Variant) As Variant

    ' 「元配列」が配列ではない場合、空配列を返して終了する。
        If Not IsArray(元配列) Then
            UDF_Transpose = Array()
            Exit Function
        End If

    ' 次元数取得用。
    Dim 仮受け As Long
    ' 元配列の次元数。
    Dim 次元数 As Long
    Dim i As Long: i = 1
        ' 一次元から順に添え字(インデックス)の最大値を取得。
        ' 存在しない次元の最大値を要求してエラーになることを
        ' 利用しているため、いったんエラーを無視している。
        On Error Resume Next
        Do
            ' 添え字の最大値取得。
            仮受け = UBound(元配列, i)
            i = i + 1
        Loop While Err.Number = 0 ' ← エラーが発生しない限り繰り返す。
        
        ' エラー無視設定を解除。
        On Error GoTo 0
        ' 正常ループ時に1、異常発生時に1を加えているため、i-2 が次元数となる。
        次元数 = i - 2

    ' 行列を入れ替えた情報を仮置きする配列。
    Dim 仮配列() As Variant
    Dim 行番号 As Long
    Dim 列番号 As Long
        
        Select Case 次元数
            
            ' 要素数がn個の一次元配列は、n行1列の二次元配列に変換する。
            Case 1
                ReDim 仮配列(1 To UBound(元配列, 1) - LBound(元配列, 1) + 1, 1 To 1)
                For 行番号 = 1 To UBound(仮配列, 1)
                    仮配列(行番号, 1) = 元配列(行番号 + LBound(元配列, 1) - 1)
                Next
            
            ' 二次元配列の場合。
            Case 2
                ' n行1列の配列に限り、要素数n個の一次元配列に変換する。
                ' ※本家本元のTranspose関数に倣う。
                If UBound(元配列, 2) = 1 Then
                    ReDim 仮配列(1 To UBound(元配列, 1))
                    For 行番号 = 1 To UBound(仮配列, 1)
                        仮配列(行番号) = 元配列(行番号 + LBound(元配列, 1) - 1, 1)
                    Next
                Else
                    ReDim 仮配列(1 To UBound(元配列, 2) - LBound(元配列, 2) + 1, _
                                 1 To UBound(元配列, 1) - LBound(元配列, 1) + 1)
                    For 行番号 = 1 To UBound(仮配列, 1)
                        For 列番号 = 1 To UBound(仮配列, 2)
                            仮配列(行番号, 列番号) = 元配列(列番号 + LBound(元配列, 2) - 1, _
                                                            行番号 + LBound(元配列, 1) - 1)
                        Next
                    Next
                End If
            
            ' 三次元以上の場合、空配列を返す。
            Case Else
                UDF_Transpose = Array()
        
        End Select
        
        UDF_Transpose = 仮配列
End Function

前回の限界がこちら。
f:id:Infoment:20200820231540p:plain

それでは、限界を突破できるか試してみよう。

Sub Test()
    Dim arr(1, 1) As Variant
    Dim i As Long
    Dim temp As Variant
    
        On Error Resume Next
        Do
            i = i + 1
            arr(0, 0) = WorksheetFunction.Rept("あ", i)
            temp = UDF_Transpose(arr)
            If i = 40000 Then
                MsgBox "40000突破!"
                Exit Sub
            End If
        Loop While Err.Number = 0
        
        MsgBox i - 1 & " 個が限界です"
End Sub

f:id:Infoment:20200829165228p:plain

今後は、こちらで対応するとしよう。

参考まで。