VB6を使用していますが、ReDim Preserveを多次元配列に行う必要があります。
Dim n, m As Integer
n = 1
m = 0
Dim arrCity() As String
ReDim arrCity(n, m)
n = n + 1
m = m + 1
ReDim Preserve arrCity(n, m)
書いたとおりに行うと、次のエラーが発生します。
ランタイムエラー9:範囲外の添字
最後の配列次元のみを変更できるため、タスクでは配列全体(この例では2次元)を変更する必要があります!
これに対する回避策または別の解決策はありますか?
正しく指摘すると、ReDim Preserve
配列の最後の次元のみ(MSDNの- ReDimステートメント ):
Preserveキーワードを使用する場合、サイズ変更できるのは最後の配列次元のみであり、次元数をまったく変更することはできません。たとえば、配列に1つの次元しかない場合、その次元は最後で唯一の次元であるため、その次元のサイズを変更できます。ただし、配列に2つ以上の次元がある場合、最後の次元のみのサイズを変更しても、配列の内容を保持できます
したがって、決定する最初の問題は、2次元配列がジョブに最適なデータ構造であるかどうかです。おそらく、1次元配列は、ReDim Preserve
?
別の方法は、 Pieter Geerkensの提案 に従ってギザギザの配列を使用することです。 VB6ではギザギザの配列を直接サポートしていません。 VB6で「配列の配列」をコーディングする1つの方法は、Variant
の配列を宣言し、各要素を目的のタイプの配列(あなたの場合はString
)にすることです。デモコードは次のとおりです。
さらに別のオプションは、Preserve
部分を独自に実装することです。そのためには、保存するデータのコピーを作成し、それを再次元化された配列に入力する必要があります。
Option Explicit
Public Sub TestMatrixResize()
Const MAX_D1 As Long = 2
Const MAX_D2 As Long = 3
Dim arr() As Variant
InitMatrix arr, MAX_D1, MAX_D2
PrintMatrix "Original array:", arr
ResizeMatrix arr, MAX_D1 + 1, MAX_D2 + 1
PrintMatrix "Resized array:", arr
End Sub
Private Sub InitMatrix(a() As Variant, n As Long, m As Long)
Dim i As Long, j As Long
Dim StringArray() As String
ReDim a(n)
For i = 0 To n
ReDim StringArray(m)
For j = 0 To m
StringArray(j) = i * (m + 1) + j
Next j
a(i) = StringArray
Next i
End Sub
Private Sub PrintMatrix(heading As String, a() As Variant)
Dim i As Long, j As Long
Dim s As String
Debug.Print heading
For i = 0 To UBound(a)
s = ""
For j = 0 To UBound(a(i))
s = s & a(i)(j) & "; "
Next j
Debug.Print s
Next i
End Sub
Private Sub ResizeMatrix(a() As Variant, n As Long, m As Long)
Dim i As Long
Dim StringArray() As String
ReDim Preserve a(n)
For i = 0 To n - 1
StringArray = a(i)
ReDim Preserve StringArray(m)
a(i) = StringArray
Next i
ReDim StringArray(m)
a(n) = StringArray
End Sub
VB6はVBAに非常に似ているため、ReDim
を使用して2次元配列にTranspose
を使用するのにそれほど多くのコードを必要としないソリューションがあると思います。
ソリューション(VBA):
Dim n, m As Integer
n = 2
m = 1
Dim arrCity() As Variant
ReDim arrCity(1 To n, 1 To m)
m = m + 1
ReDim Preserve arrCity(1 To n, 1 To m)
arrCity = Application.Transpose(arrCity)
n = n + 1
ReDim Preserve arrCity(1 To m, 1 To n)
arrCity = Application.Transpose(arrCity)
OPの質問と異なる点は、arrCity
配列の下限は0ではなく1です。これは、Application.Transpose
に仕事をさせるためです。
VB6にはTranspose
メソッドが必要だと思います。
これに関して:
「私のタスクでは、配列全体(2次元)を変更する必要があります」
ギザギザの配列(つまり、値の配列の配列)を使用するだけです。その後、必要に応じて寸法を変更できます。おそらくもう少し作業が、解決策。
これらの答えのすべてをテストしたわけではありませんが、これを達成するために複雑な機能を使用する必要はありません。それよりもずっと簡単です!以下の私のコードは、すべてのオフィスVBAアプリケーション(Word、Access、Excel、Outlookなど)で動作し、非常に簡単です。お役に立てれば:
''Dimension 2 Arrays
Dim InnerArray(1 To 3) As Variant ''The inner is for storing each column value of the current row
Dim OuterArray() As Variant ''The outer is for storing each row in
Dim i As Byte
i = 1
Do While i <= 5
''Enlarging our outer array to store a/another row
ReDim Preserve OuterArray(1 To i)
''Loading the current row column data in
InnerArray(1) = "My First Column in Row " & i
InnerArray(2) = "My Second Column in Row " & i
InnerArray(3) = "My Third Column in Row " & i
''Loading the entire row into our array
OuterArray(i) = InnerArray
i = i + 1
Loop
''Example print out of the array to the Intermediate Window
Debug.Print OuterArray(1)(1)
Debug.Print OuterArray(1)(2)
Debug.Print OuterArray(2)(1)
Debug.Print OuterArray(2)(2)
私はこれが少し古いことを知っていますが、追加のコーディングを必要としないはるかに簡単なソリューションがあるかもしれないと思います:
転置、再配置、再転置の代わりに、2次元配列について説明する場合は、最初に転置された値だけを保存してください。その場合、redim preserveは実際には最初から右(2番目)の次元を増やします。または、言い換えれば、それを視覚化するために、列のnrのみをredim preserveで増やすことができる場合は、2列ではなく2行で保存してください。
インデックスは、00-01、10-11、20-21ではなく00-01、01-11、02-12、03-13、04-14、05-15 ... 0 25-1 25などです、30-31、40-41など。
再保存する必要があるディメンションが1つだけである限り、アプローチは引き続き機能します。そのディメンションを最後に置くだけです。
2番目の(または最後の)次元のみがリダイム中に保持できるため、これが配列の使用方法を最初から想定していると主張することができます。私はどこでもこの解決策を見たことがないので、何かを見落としているかもしれませんか?
(2つの次元に関する同様の質問に以前に投稿し、より多くの次元についてはここに回答を拡張しました)
内部配列となる文字列の配列を含むユーザー定義型を使用できます。次に、このユーザー定義型の配列を外部配列として使用できます。
次のテストプロジェクトをご覧ください。
'1 form with:
' command button: name=Command1
' command button: name=Command2
Option Explicit
Private Type MyArray
strInner() As String
End Type
Private mudtOuter() As MyArray
Private Sub Command1_Click()
'change the dimensens of the outer array, and fill the extra elements with "1"
Dim intOuter As Integer
Dim intInner As Integer
Dim intOldOuter As Integer
intOldOuter = UBound(mudtOuter)
ReDim Preserve mudtOuter(intOldOuter + 2) As MyArray
For intOuter = intOldOuter + 1 To UBound(mudtOuter)
ReDim mudtOuter(intOuter).strInner(intOuter) As String
For intInner = 0 To UBound(mudtOuter(intOuter).strInner)
mudtOuter(intOuter).strInner(intInner) = "1"
Next intInner
Next intOuter
End Sub
Private Sub Command2_Click()
'change the dimensions of the middle inner array, and fill the extra elements with "2"
Dim intOuter As Integer
Dim intInner As Integer
Dim intOldInner As Integer
intOuter = UBound(mudtOuter) / 2
intOldInner = UBound(mudtOuter(intOuter).strInner)
ReDim Preserve mudtOuter(intOuter).strInner(intOldInner + 5) As String
For intInner = intOldInner + 1 To UBound(mudtOuter(intOuter).strInner)
mudtOuter(intOuter).strInner(intInner) = "2"
Next intInner
End Sub
Private Sub Form_Click()
'clear the form and print the outer,inner arrays
Dim intOuter As Integer
Dim intInner As Integer
Cls
For intOuter = 0 To UBound(mudtOuter)
For intInner = 0 To UBound(mudtOuter(intOuter).strInner)
Print CStr(intOuter) & "," & CStr(intInner) & " = " & mudtOuter(intOuter).strInner(intInner)
Next intInner
Print "" 'add an empty line between the outer array elements
Next intOuter
End Sub
Private Sub Form_Load()
'init the arrays
Dim intOuter As Integer
Dim intInner As Integer
ReDim mudtOuter(5) As MyArray
For intOuter = 0 To UBound(mudtOuter)
ReDim mudtOuter(intOuter).strInner(intOuter) As String
For intInner = 0 To UBound(mudtOuter(intOuter).strInner)
mudtOuter(intOuter).strInner(intInner) = CStr((intOuter + 1) * (intInner + 1))
Next intInner
Next intOuter
WindowState = vbMaximized
End Sub
プロジェクトを実行し、フォームをクリックして配列の内容を表示します。
Command1をクリックして外側の配列を拡大し、フォームをクリックして結果を表示します。
Command2をクリックして内部配列を拡大し、フォームをもう一度クリックして結果を表示します。
ただし注意してください:外側の配列を再利用するときは、外側の配列のすべての新しい要素の内側の配列も再利用する必要があります
私はこの問題に出くわしましたが、自分自身でこの障害にぶつかりました。最終的に、この_ReDim Preserve
_を新しいサイズの配列(最初または最後の次元)で処理するためのコードを実際にすばやく記述しました。たぶん同じ問題に直面している他の人を助けるでしょう。
そのため、使用法として、配列を元々MyArray(3,5)
として設定し、寸法を(最初も!)大きくしたい場合は、MyArray(10,20)
とだけ言ってみましょう。あなたはこのようなことをすることに慣れていますか?
_ ReDim Preserve MyArray(10,20) '<-- Returns Error
_
しかし、残念ながら、最初の次元のサイズを変更しようとしたため、エラーが返されます。だから私の関数では、代わりにこのようなことをするでしょう:
_ MyArray = ReDimPreserve(MyArray,10,20)
_
配列が大きくなり、データが保持されます。多次元配列の_ReDim Preserve
_が完成しました。 :)
そして最後に、奇跡的な関数:ReDimPreserve()
_'redim preserve both dimensions for a multidimension array *ONLY
Public Function ReDimPreserve(aArrayToPreserve,nNewFirstUBound,nNewLastUBound)
ReDimPreserve = False
'check if its in array first
If IsArray(aArrayToPreserve) Then
'create new array
ReDim aPreservedArray(nNewFirstUBound,nNewLastUBound)
'get old lBound/uBound
nOldFirstUBound = uBound(aArrayToPreserve,1)
nOldLastUBound = uBound(aArrayToPreserve,2)
'loop through first
For nFirst = lBound(aArrayToPreserve,1) to nNewFirstUBound
For nLast = lBound(aArrayToPreserve,2) to nNewLastUBound
'if its in range, then append to new array the same way
If nOldFirstUBound >= nFirst And nOldLastUBound >= nLast Then
aPreservedArray(nFirst,nLast) = aArrayToPreserve(nFirst,nLast)
End If
Next
Next
'return the array redimmed
If IsArray(aPreservedArray) Then ReDimPreserve = aPreservedArray
End If
End Function
_
これは20分ほどで書いたので、保証はありません。ただし、使用または拡張する場合は、お気軽に。私は誰かがこのようなコードをすでにここに持っているだろうと思っていたでしょう。だからここで仲間のギアヘッドに行きます。
これはよりコンパクトで、配列の最初の最初の位置を尊重し、初期値を使用して古い値を追加します。
Public Sub ReDimPreserve(ByRef arr, ByVal size1 As Long, ByVal size2 As Long)
Dim arr2 As Variant
Dim x As Long, y As Long
'Check if it's an array first
If Not IsArray(arr) Then Exit Sub
'create new array with initial start
ReDim arr2(LBound(arr, 1) To size1, LBound(arr, 2) To size2)
'loop through first
For x = LBound(arr, 1) To UBound(arr, 1)
For y = LBound(arr, 2) To UBound(arr, 2)
'if its in range, then append to new array the same way
arr2(x, y) = arr(x, y)
Next
Next
'return byref
arr = arr2
End Sub
この行でこのサブルーチンを呼び出して、最初の次元のサイズを変更します
ReDimPreserve arr2, UBound(arr2, 1) + 1, UBound(arr2, 2)
他のテストを追加して、初期サイズが新しい配列よりも大きくないかどうかを確認できます。私の場合は必要ありません
VBAでこれを行う最も簡単な方法は、配列、新しい行数、および新しい列数を取り込む関数を作成することです。
以下の関数を実行して、サイズ変更後にすべての古いデータをアレイにコピーして戻します。
function dynamic_preserve(array1, num_rows, num_cols)
dim array2 as variant
array2 = array1
reDim array1(1 to num_rows, 1 to num_cols)
for i = lbound(array2, 1) to ubound(array2, 2)
for j = lbound(array2,2) to ubound(array2,2)
array1(i,j) = array2(i,j)
next j
next i
dynamic_preserve = array1
end function