VBAでは.NETのSystem.Collections.ArrayListを使うことができますが、環境によって動かなかったりします。
それを解決するため、クラスでArrayListを実装したのでこの記事で紹介していきます。
クラス概要
Java, Python, Ruby, C#などを参考に、自分が欲しいと思う機能をほぼ実装しました。
ポイントとしては以下の通りです。
・map, filter, flattenの実装
・pythonのようにマイナスのインデックスに対応 (-1は末尾の要素を指す)
・ソートアルゴリズムはクイックソート
・ワークシートへの読み書きに対応
・ToStringの実装、要素を簡単に出力できる
・Grepで要素を選択可能
・シャッフル、ランダムな値取得
・uniqの実装
など
使用例
簡単に使用例を紹介します
Set arr as New ArrayList arr.Add 1 arr.AddValues 2, 3, 4 arr.Add Array(5, 6, 7) arr.Dump ' => [1, 2, 3, 4, [5, 6, 7]] arr.Flatten.Dump ' => [1, 2, 3, 4, 5, 6, 7]
Dumpメソッドで簡単に要素を出力できます。
メソッド一覧 (全51個)
メソッド名 | 説明 |
---|---|
Add | 末尾に要素を追加する |
AddValues | 可変長引数で末尾に要素を一括追加する |
AddRange | 末尾に指定した配列の要素をすべて追加する |
AsList | 配列をArrayListに変換する |
Clear | 要素をすべて削除する |
Clone | このリストをコピーして返す |
Compact | Null, Emptyをすべて取り除いたリストを返す |
Contains | 指定した要素が含まれているならTrueを返す |
CopyBy | 指定した配列をこのリストにコピーする |
Count | 要素数を返す |
CountItem | 指定した要素を数える |
CreateList | 指定した要素数でこのリストを初期化する |
Drop | 先頭からn要素を捨てて残りを返す |
Dump | このリストをイミディエイトウィンドウに出力する |
Filter | 各要素に対して関数を評価した値がTrueの要素だけを取得する |
First | 先頭の要素を返す |
Flatten | ネストした配列を一次元の配列に変換する |
GetItem | 要素を取得する |
GetItemAsList | リストとして要素を取得する |
Grep | 正規表現にマッチする要素を返す |
Grep_v | 正規表現にマッチしない要素を返す |
IndexOf | 指定した値の左からのインデックスを返す |
Insert | 指定した場所に要素を挿入する |
IsNumericArray | 数値だけのリストならTrue |
Join | 要素を指定した文字列で結合する |
Last | 末尾の値を返す |
LastIndexOf | 指定した値の右からのインデックスを返す |
Map | 各要素に対して関数を評価したリストを返す |
Max | 最大値を返す |
Min | 最小値を返す |
Pop | 末尾から要素を取得する |
ReadArrayFromWorkSheet | ワークシートから配列を読み込む |
Remove | 指定した要素を一つ削除する |
RemoveAll | 指定した要素をすべて削除する |
RemoveAt | 指定した場所の要素を削除する |
Reverse | 要素を逆順にする |
Reversed | 要素を逆順にしたリストを返す |
Sample | 指定数ランダムに選んで取得する |
SetItem | 指定した場所に要素をセットする |
Shuffle | シャッフルする |
Shuffled | シャッフルしたりストを返す |
Slice | 部分リストを返す |
Sort | 昇順にソートする |
Sorted | 昇順にソートしたリストを返す |
Sum | 要素を合計した値を返す |
Take | 先頭からn要素を取得する |
ToArray | 動的配列に変換する |
ToNumericList | 数値だけのリストに変換する |
ToString | 文字列表現に変換する |
Uniq | 重複した要素を削除する |
WriteArrayToWorkSheet | ワークシートにこのリストを書き込む |
ソースコード
1600行ほどあるのでかなり長いです。
ちなみにダブルクリックで全選択できます。
' ' 動的配列への操作を抽象化するクラス ' Option Explicit Option Base 0 Private array_ As Variant ' ' このリストのコンストラクタ ' Private Sub Class_Initialize() array_ = Array() End Sub ' ' このリストのデストラクタ ' Private Sub Class_Terminate() Erase array_ End Sub ' ' 指定要素数のリストを初期化する ' 2次元配列まで対応 ' Public Sub CreateList(w As LongPtr, Optional h As LongPtr = 1, Optional init As Variant = Null) Dim i As LongPtr Dim j As LongPtr Dim ret As New ArrayList Dim temp As New ArrayList Me.Clear If h <= 1 Then For i = 1 To w ret.Add init Next Else For i = 1 To h temp.Clear For j = 1 To w temp.Add init Next ret.Add temp Next End If Me.CopyBy ret End Sub ' ' このリストの末尾に指定した要素を追加する ' Public Sub Add(value As Variant) Dim item As Variant ' 引数にArrayListが指定された場合は配列に変換する If TypeName(value) = TypeName(Me) Then item = value.ToArray ' 引数にObjectが指定された場合は例外を起こす ElseIf IsObject(value) Then Err.Raise 13 ' 引数に静的配列が指定された場合は動的配列に変換する ElseIf IsArray(value) Then item = StaticArrayToDynamicArray(value) Else item = value End If ReDim Preserve array_(UBound(array_) + 1) array_(UBound(array_)) = item End Sub ' ' このリストの末尾に指定した要素を可変長引数で追加する ' Public Sub AddValues(ParamArray values() As Variant) Dim value As Variant For Each value In values Me.Add value Next End Sub ' ' このリストの末尾に指定した配列の要素を追加する ' Public Sub AddRange(arr As Variant) Dim seq As Variant Dim item As Variant If TypeName(arr) = TypeName(Me) Then seq = arr.ToArray ElseIf IsArray(arr) Then seq = StaticArrayToDynamicArray(arr) ElseIf Not IsArray(arr) Then seq = Array(arr) Else seq = arr End If For Each item In seq Me.Add item Next End Sub ' ' このリストの指定した位置に指定した要素を挿入する ' Public Sub Insert(idx As LongPtr, value As Variant) Dim item As Variant Dim i As LongPtr Dim length As LongPtr idx = ConvIdx(idx) If idx < 0 Or idx > UBound(array_) Then Err.Raise 9 End If ReDim Preserve array_(UBound(array_) + 1) length = UBound(array_) For i = length To idx Step -1 If i > idx Then array_(i) = array_(i - 1) Else array_(i) = value End If Next End Sub ' ' 特定の要素がこのリスト内にあるときに、最初に出現したものを削除する ' Public Sub Remove(value As Variant) Dim item As Variant Dim i As LongPtr Dim length As LongPtr length = UBound(array_) For i = 0 To length If IsSameValue(array_(i), value) Then Me.RemoveAt i Exit For End If Next End Sub ' ' このリストから指定した要素をすべて削除する ' Public Sub RemoveAll(value As Variant) Dim item As Variant Dim i As LongPtr Dim length As LongPtr length = UBound(array_) For i = length To 0 Step -1 If IsSameValue(array_(i), value) Then Me.RemoveAt i End If Next End Sub ' ' このリストの指定された位置にある要素を削除する ' Public Sub RemoveAt(idx As LongPtr) Dim i As LongPtr Dim length As LongPtr length = Me.Count idx = ConvIdx(idx) If idx < 0 Or idx >= length Then Err.Raise 9 End If For i = idx + 1 To length - 1 array_(i - 1) = array_(i) Next If length > 1 Then ReDim Preserve array_(UBound(array_) - 1) Else Me.Clear End If End Sub ' ' このリストの要素をすべて削除して空にする ' Public Sub Clear() Erase array_ array_ = Array() End Sub ' ' 指定された要素がこのリスト内で最初に検出された位置のインデックスを返す ' 指定された要素がこのリストに存在しない場合は -1 を返す ' Public Function IndexOf(value As Variant) As LongPtr Dim item As Variant Dim i As LongPtr Dim length As LongPtr length = UBound(array_) For i = 0 To length item = array_(i) If IsSameValue(item, value) Then IndexOf = i Exit Function End If Next IndexOf = -1 End Function ' ' 指定された要素がこのリスト内で最後に検出された位置のインデックスを返す ' 指定された要素がこのリストに存在しない場合は -1 を返す ' Public Function LastIndexOf(value As Variant) As LongPtr Dim item As Variant Dim i As LongPtr Dim length As LongPtr length = UBound(array_) For i = length To 0 Step -1 item = array_(i) If IsSameValue(item, value) Then LastIndexOf = i Exit Function End If Next LastIndexOf = -1 End Function ' ' このリストの要素数を返す ' Public Function Count() As LongPtr Count = UBound(array_) + 1 End Function ' ' このリストに指定した要素がいくつ含まれているかを返す ' Public Function CountItem(value As Variant) As LongPtr Dim total As LongPtr Dim item As Variant For Each item In array_ If IsSameValue(item, value) Then total = total + 1 End If Next CountItem = total End Function ' ' このリストに指定した要素が含まれているならTrueを返す ' Public Function Contains(value As Variant) As Boolean Dim item As Variant For Each item In array_ If IsSameValue(item, value) Then Contains = True Exit Function End If Next Contains = False End Function ' ' このリストの指定位置の要素を返す ' Public Function GetItem(idx As LongPtr) As Variant idx = ConvIdx(idx) GetItem = array_(idx) End Function ' ' このリストの指定位置の要素をArrayListに変換して返す ' Public Function GetItemAsList(idx As LongPtr) As ArrayList Dim ret As New ArrayList idx = ConvIdx(idx) ret.AddRange array_(idx) Set GetItemAsList = ret End Function ' ' このリストの指定位置に要素をセットする ' Public Sub SetItem(idx As LongPtr, value As Variant) idx = ConvIdx(idx) array_(idx) = value End Sub ' ' このリストの指定された位置にある要素をリストから削除して、その要素を返す ' インデックスが指定されない場合は、リストの末尾の要素を削除して返す ' Public Function Pop(Optional idx As LongPtr = -1) As Variant idx = ConvIdx(idx) Pop = array_(idx) Me.RemoveAt idx End Function ' ' このリストの要素を指定数ランダムに選んでArrayListとして返す ' Public Function Sample(Optional n As LongPtr = 1) As ArrayList Dim i As LongPtr Dim temp As ArrayList Dim ret As New ArrayList Set temp = Me.Clone temp.Shuffle For i = 1 To n ret.Add temp.Pop Next Set Sample = ret End Function ' ' このリストの要素を逆順にする ' Public Sub Reverse() Dim rIdx As LongPtr Dim lIdx As LongPtr rIdx = 0 lIdx = Me.Count - 1 While rIdx < lIdx Swap rIdx, lIdx rIdx = rIdx + 1 lIdx = lIdx - 1 Wend End Sub ' ' このリストの要素を逆順にしたリストを返す ' Public Function Reversed() As ArrayList Dim ret As ArrayList Set ret = Me.Clone ret.Reverse Set Reversed = ret End Function ' ' このリストの要素をシャッフルする ' Public Sub Shuffle() Dim i As LongPtr Dim r As LongPtr Dim length As LongPtr length = Me.Count For i = length - 1 To 2 Step -1 r = Rnd * 10000 + length r = r Mod (i - 1) Swap r, i Next End Sub ' ' このリストの要素をシャッフルしたリストを返す ' Public Function Shuffled() As ArrayList Dim ret As ArrayList Set ret = Me.Clone ret.Shuffle Set Shuffled = ret End Function ' ' このリストの要素を昇順で並び替える ' Public Sub Sort() If Me.IsNumericArray() Then Call SortByNumeric Else Call SortByString End If End Sub ' ' このリストの要素を昇順で並び替えたリストを返す ' Public Function Sorted() As ArrayList Dim ret As ArrayList Set ret = Me.Clone ret.Sort Set Sorted = ret End Function ' ' このリストを数値の配列とみなして最大値を返す ' Public Function Max() As Double Dim item As Variant Dim prev As Double Dim i As LongPtr ' リストに数値以外が含まれている場合はエラー If Me.IsNumericArray = False Then Err.Raise 13 End If ' リストに要素が無い場合はエラー If Me.Count = 0 Then Err.Raise 9 End If prev = -1E+18 For Each item In array_ If item > prev Then prev = item End If Next Max = prev End Function ' ' このリストを数値の配列とみなして最小値を返す ' Public Function Min() As Double Dim item As Variant Dim prev As Double Dim i As LongPtr ' リストに数値以外が含まれている場合はエラー If Me.IsNumericArray = False Then Err.Raise 13 End If ' リストに要素が無い場合はエラー If Me.Count = 0 Then Err.Raise 9 End If prev = 1E+32 For Each item In array_ If CDbl(item) < prev Then prev = item End If Next Min = prev End Function ' ' このリストを数値の配列とみなして合計値を返す ' Public Function Sum() As Double Dim item As Variant Dim total As Double ' リストに数値以外が含まれている場合はエラー If Me.IsNumericArray = False Then Err.Raise 13 End If ' リストに要素が無い場合はエラー If Me.Count = 0 Then Err.Raise 9 End If For Each item In array_ total = total + CDbl(item) Next Sum = total End Function ' ' このリストの先頭の要素を取得する ' 要素数が0の時はEmptyを返す ' Public Function First() As Variant If Me.Count = 0 Then First = Empty Else First = array_(0) End If End Function ' ' このリストの末尾の要素を取得する ' 要素数が0の時はEmptyを返す ' Public Function Last() As Variant If Me.Count = 0 Then Last = Empty Else Last = array_(ConvIdx(-1)) End If End Function ' ' このリストの重複した要素を取り除いたリストを返す ' Public Function Uniq() As ArrayList Dim item As Variant Dim prev As Variant Dim i As LongPtr Dim length As LongPtr Dim temp As ArrayList Dim ret As New ArrayList Set temp = Me.Sorted length = temp.Count If length = 0 Then Exit Function End If prev = temp.GetItem(0) ret.Add prev For i = 1 To length - 1 item = temp.GetItem(i) If Not IsSameValue(prev, item) Then ret.Add item End If prev = item Next Set Uniq = ret End Function ' ' このリストを再帰的に平坦化したリストを生成して返す ' Public Function Flatten() As ArrayList Dim ret As New ArrayList Dim tmp As New ArrayList Dim item As Variant For Each item In array_ If IsArray(item) Then tmp.CopyBy item ret.AddRange tmp.Flatten Else ret.Add item End If Next Set Flatten = ret End Function ' ' このリストからNull, Emptyを取り除いたリストを返す ' Public Function Compact() As ArrayList Dim item As Variant Dim ret As New ArrayList For Each item In array_ If IsNull(item) Or IsEmpty(item) Then Else ret.Add item End If Next Set Compact = ret End Function ' ' 各要素に対して関数を評価した結果を全て含むリストを返す ' Public Function Map(obj As Object, funcname As String) As ArrayList Dim ret As New ArrayList Dim item As Variant For Each item In array_ ret.Add CallByName(obj, funcname, VbMethod, item) Next Set Map = ret End Function ' ' 各要素に対して関数を評価した値がTrueであった要素を全て含む配列を返す ' Trueになる要素がなかった場合は空の配列を返す ' Public Function Filter(obj As Object, funcname As String) As ArrayList Dim ret As New ArrayList Dim item As Variant For Each item In array_ If CallByName(obj, funcname, VbMethod, item) Then ret.Add item End If Next Set Filter = ret End Function ' ' このリストの要素を文字列とみなし、正規表現に一致する要素を選択したリストを返す ' Public Function Grep(pattern As String) As ArrayList On Error Resume Next Dim re As Object Dim ret As New ArrayList Dim item As Variant Set re = CreateObject("VBScript.RegExp") re.pattern = pattern For Each item In array_ item = CStr(item) If re.Test(item) = True Then ret.Add item End If Next Set re = Nothing Set Grep = ret End Function ' ' このリストの要素を文字列とみなし、正規表現に一致しない要素を選択したリストを返す ' Public Function Grep_v(pattern As String) As ArrayList On Error Resume Next Dim re As Object Dim ret As New ArrayList Dim item As Variant Set re = CreateObject("VBScript.RegExp") re.pattern = pattern For Each item In array_ item = CStr(item) If re.Test(item) = False Then ret.Add item End If Next Set re = Nothing Set Grep_v = ret End Function ' ' このリストの要素を文字列sepを間に挟んで連結した文字列を返す ' Public Function Join(Optional sep = " ") As String Dim temp As String Dim item As Variant For Each item In array_ temp = temp & item & sep Next temp = Left(temp, Len(temp) - Len(sep)) Join = temp End Function ' ' idxStartからindexEndまでの要素を取り出したリストを返す ' Public Function Slice(idxStart As LongPtr, idxEnd As LongPtr, Optional step As LongPtr = 1) As ArrayList Dim i As LongPtr Dim ret As New ArrayList idxStart = ConvIdx(idxStart) idxEnd = ConvIdx(idxEnd) If step = 0 Then Set Slice = ret Exit Function End If For i = idxStart To idxEnd Step step ret.Add array_(i) Next Set Slice = ret End Function ' ' このリストの先頭から n 要素をArrayListとして返す ' Public Function Take(n As LongPtr) As ArrayList Dim item As Variant Dim i As LongPtr Dim length As LongPtr Dim ret As New ArrayList length = Me.Count For i = 0 To length - 1 item = array_(i) If i = n Then Exit For End If ret.Add item Next Set Take = ret End Function ' ' 配列の先頭の n 要素を捨て、残りの要素をArrayListとして返す ' Public Function Drop(n As LongPtr) As ArrayList Dim item As Variant Dim i As LongPtr Dim length As LongPtr Dim ret As New ArrayList length = Me.Count For i = n To length - 1 item = array_(i) ret.Add item Next Set Drop = ret End Function ' ' 指定した要素をリストに変換して返す ' Public Function AsList(value As Variant) As ArrayList Dim ret As New ArrayList ret.AddRange value Set AsList = ret End Function ' ' このリストを複製する ' Public Function Clone() As ArrayList Dim ret As New ArrayList ret.CopyBy array_ Set Clone = ret End Function ' ' このリストに要素をコピーする ' Public Sub CopyBy(value As Variant) Me.Clear Me.AddRange value End Sub ' ' 指定したワークシートから配列を読み込む ' ワークシートを指定しない場合はActiveSheetを指定したとする ' Public Sub ReadArrayFromWorkSheet(pos As String, Optional sheet As Worksheet = Nothing) If sheet Is Nothing Then Set sheet = ActiveSheet End If Me.Clear Me.AddRange StaticArrayToDynamicArray(sheet.Range(pos).value, True) End Sub ' ' ワークシートの指定した範囲にこのリストの要素を書き出す ' ワークシートを指定しない場合はActiveSheetを指定したとする ' 二次元配列に書き出す場合、左上から左->右とセルに代入していく ' Public Sub WriteArrayToWorkSheet(pos As String, Optional sheet As Worksheet = Nothing) Dim i As LongPtr Dim j As LongPtr Dim temp As Variant Dim elms As New ArrayList Set elms = Me.Flatten If sheet Is Nothing Then Set sheet = ActiveSheet End If temp = sheet.Range(pos).value For i = LBound(temp, 1) To UBound(temp, 1) For j = LBound(temp, 2) To UBound(temp, 2) If elms.Count > 0 Then temp(i, j) = elms.Pop(0) Else temp(i, j) = Empty End If Next Next sheet.Range(pos) = temp End Sub ' ' このリストの要素が数値だけの場合Trueを返す ' Public Function IsNumericArray() As Boolean Dim item As Variant For Each item In array_ If Not IsNumeric(item) Then IsNumericArray = False Exit Function End If Next IsNumericArray = True End Function ' ' このリストの要素を文字列に変換して返す ' Public Function ToString() As String Dim ret As String Dim i As LongPtr Dim item As Variant Dim length As LongPtr length = Me.Count If length = 0 Then ToString = "[]" Exit Function End If ret = "[" For i = 0 To length - 2 item = array_(i) ret = ret & ConvertItemToString(item) & ", " Next item = array_(length - 1) ret = ret & ConvertItemToString(item) & "]" ToString = ret End Function ' ' このリストの数値の要素のみを選択したリストを返す ' Public Function ToNumericList() As ArrayList Dim ret As New ArrayList Dim item As Variant For Each item In array_ If IsNumeric(item) Then If item <> Empty Then ret.Add item End If End If Next Set ToNumericList = ret End Function ' ' このリストを動的配列に変換して返す ' Public Function ToArray() As Variant ToArray = array_ End Function ' ' このリストの全ての要素をイミディエイトウィンドウに出力する ' Public Sub Dump() Debug.Print Me.ToString End Sub ' ' * Private Methods * ' ' ' このリストの要素の位置を交換する ' Private Sub Swap(idx1 As LongPtr, idx2 As LongPtr) Dim temp As Variant temp = array_(idx1) array_(idx1) = array_(idx2) array_(idx2) = temp End Sub ' ' 指定した要素の文字列表現を返す ' Private Function ConvertItemToString(value As Variant) Dim ret As String ' 引数が文字列の場合 If TypeName(value) = "String" Then value = Replace(value, vbCrLf, "\r\n") value = Replace(value, vbLf, "\n") value = Replace(value, vbCr, "\r") value = Replace(value, """", "\""") ret = """" & value & """" ' 引数が配列の場合 ElseIf IsArray(value) Then Dim temp As New ArrayList temp.CopyBy value ret = temp.ToString ' 引数がEmptyの場合 ElseIf IsEmpty(value) Then ret = "Empty" ' 引数がNullの場合 ElseIf IsNull(value) Then ret = "Null" ' 引数がオブジェクトの場合 ElseIf IsObject(value) Then ret = "<" & TypeName(value) & " object at " & ObjPtr(value) & ">" ' 引数がBooleanの場合 ElseIf TypeName(value) = "Boolean" Then ret = StrConv(value, vbProperCase) ' 引数がエラーの場合 ElseIf IsError(value) Then ret = "<error """ & TypeName(value) & """>" ' 引数がDateの場合 ElseIf IsDate(value) Then ret = value ' 引数が数値の場合 ElseIf IsNumeric(value) Then ret = value ' その他の場合 Else ret = """" & value & """" End If ConvertItemToString = ret End Function ' ' 配列同士の比較をする ' Private Function IsSameArray(a As Variant, b As Variant) As Boolean Dim i As LongPtr Dim length As LongPtr Dim arrA As New ArrayList Dim arrB As New ArrayList Dim itemA As Variant Dim itemB As Variant arrA.AddRange a arrB.AddRange b If arrA.Count <> arrB.Count Then IsSameArray = False Exit Function End If If arrA.Count = 0 And arrB.Count = 0 Then IsSameArray = True Exit Function End If length = arrA.Count For i = 0 To length - 1 itemA = arrA.GetItem(i) itemB = arrB.GetItem(i) If IsArray(itemA) Or IsArray(itemB) Then If IsArray(itemA) And IsArray(itemB) Then If Not IsSameArray(itemA, itemB) Then IsSameArray = False Exit Function End If Else IsSameArray = False Exit Function End If Else If itemA <> itemB Then IsSameArray = False Exit Function End If End If Next IsSameArray = True End Function ' ' 配列, オブジェクト, 値の差を気にせず比較できるようにする ' Private Function IsSameValue(a As Variant, b As Variant) As Boolean Dim ret As Boolean ' 配列同士の比較 If IsArray(a) Or IsArray(b) Then If IsArray(a) And IsArray(b) Then ret = IsSameArray(a, b) Else ret = False End If ' オブジェクト同士の比較 ElseIf IsObject(a) Or IsObject(b) Then If IsObject(a) And IsObject(b) Then ret = ObjPtr(a) = ObjPtr(b) Else ret = False End If ' Null同士の比較 ElseIf IsNull(a) Or IsNull(b) Then If IsNull(a) And IsNull(b) Then ret = True Else ret = False End If ' 値同士の比較 Else ret = a = b End If IsSameValue = ret End Function ' ' 指定した配列の次元数を取得する ' Private Function GetArrayDimension(arr As Variant) As Integer Dim size As LongPtr Dim i As LongPtr On Error GoTo L_RET While True i = i + 1 size = UBound(arr, i) - 1 Wend L_RET: GetArrayDimension = i - 1 End Function ' ' 指定した静的配列を動的配列に変換する ' 2次元まで対応 ' Private Function StaticArrayToDynamicArray(arr As Variant, Optional isWorksheet = False) As Variant Dim i As LongPtr Dim j As LongPtr Dim w As LongPtr Dim h As LongPtr Dim temp As Variant Dim item As Variant Dim ret As Variant ret = Array() If GetArrayDimension(arr) = 2 Then h = UBound(arr, 1) w = UBound(arr, 2) For i = LBound(arr, 1) To h temp = Array() For j = LBound(arr, 2) To w ReDim Preserve temp(UBound(temp) + 1) temp(UBound(temp)) = arr(i, j) Next ReDim Preserve ret(UBound(ret) + 1) ret(UBound(ret)) = temp Next ' 指定した静的配列がワークシートから取得した配列の場合は変換をかける If isWorksheet = True Then If UBound(ret) = 0 Then ret = ret(0) ElseIf UBound(ret(LBound(ret))) = 0 Then temp = Array() For Each item In ret ReDim Preserve temp(UBound(temp) + 1) temp(UBound(temp)) = item(0) Next ret = temp End If End If StaticArrayToDynamicArray = ret Else For Each item In arr ReDim Preserve ret(UBound(ret) + 1) ret(UBound(ret)) = item Next StaticArrayToDynamicArray = ret End If End Function ' ' マイナスのインデックスを変換する ' Private Function ConvIdx(n As LongPtr) As LongPtr If n >= 0 Then ConvIdx = n Else ConvIdx = Me.Count + n End If End Function ' ' このリストの要素を数値として照準で並び替える ' Private Sub SortByNumeric() Call quicksort_n(array_) End Sub ' ' このリストの要素を文字列として照準で並び替える ' Private Sub SortByString() Call quicksort_s(array_) End Sub ' ' 指定した数値の配列をクイックソートで並び変える ' Private Sub quicksort_n(ByRef data As Variant, Optional low As LongPtr = 0, Optional high As LongPtr = -100) Dim l As LongPtr Dim r As LongPtr Dim pivot As Double If high = -100 Then high = UBound(data) End If l = low r = high pivot = data((low + high) \ 2) Do While l <= r Do While CDbl(data(l)) < pivot And l < high l = l + 1 Loop Do While pivot < CDbl(data(r)) And r > low r = r - 1 Loop If l <= r Then Call Swap(l, r) l = l + 1 r = r - 1 End If Loop If low < r Then Call quicksort_n(data, low, r) End If If l < high Then Call quicksort_n(data, l, high) End If End Sub ' ' 指定した文字列の配列をクイックソートで並び変える ' Private Sub quicksort_s(ByRef data As Variant, Optional low As LongPtr = 0, Optional high As LongPtr = -100) Dim l As LongPtr Dim r As LongPtr Dim pivot As Variant If high = -100 Then high = UBound(data) End If l = low r = high pivot = ConvertItemToString(data((low + high) \ 2)) Do While l <= r Do While StrComp(ConvertItemToString(data(l)), pivot) = -1 And l < high l = l + 1 Loop Do While StrComp(ConvertItemToString(data(r)), pivot) = 1 And r > low r = r - 1 Loop If l <= r Then Call Swap(l, r) l = l + 1 r = r - 1 End If Loop If low < r Then Call quicksort_s(data, low, r) End If If l < high Then Call quicksort_s(data, l, high) End If End Sub