19

私は 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 次元) を変更する必要があります。

これに対する回避策または別の解決策はありますか?

4

11 に答える 11

9

あなたが正しく指摘しているよう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
于 2013-05-05T16:48:13.833 に答える
5

VB6 は VBA と非常に似ているため、Excel で作業している場合はReDimを使用して、2 次元配列にこれほど多くのコードを必要としないソリューションがあると思います。Transpose

解決策(Excel 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仕事をさせるためです。

Transposeは Excel オブジェクトのメソッドであることに注意してくださいApplication(実際には へのショートカットApplication.WorksheetFunction.Transposeです)。また、VBA にTransposeは 2 つの重大な制限があるため、使用する際には注意が必要です。配列に 65536 を超える要素がある場合、失敗します。いずれかの要素の長さが 256 文字を超えると、失敗します。これらのどちらも問題にならない場合、Transpose は配列形式のランクを 1D から 2D に、またはその逆に適切に変換します。

残念ながら、VB6 への「トランスポーズ」ビルドのようなものはありません。

于 2015-04-04T01:20:37.857 に答える
3

これに関して:

「私のタスクでは、配列全体 (2 次元) を変更する必要があります」

「ぎざぎざの」配列 (つまり、値の配列の配列) を使用してください。その後、必要に応じて寸法を変更できます。バリアントの 1 次元配列を持つことができ、バリアントには配列を含めることができます。

おそらくもう少し作業が必要ですが、解決策です。

于 2013-05-04T02:18:05.793 に答える
0

これはよりコンパクトで、配列の最初の位置を尊重し、初期境界を使用して古い値を追加するだけです。

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)

他のテストを追加して、初期サイズが新しい配列より大きくないかどうかを確認できます。私の場合は不要です

于 2015-01-20T17:31:21.837 に答える
0

内部配列となる文字列の配列を含むユーザー定義型を使用できます。次に、このユーザー定義型の配列を外部配列として使用できます。

次のテスト プロジェクトを見てください。

'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 をクリックして内部配列を拡大し、フォームをもう一度クリックして結果を表示します。

ただし注意してください: 外側の配列を再調整するときは、外側の配列のすべての新しい要素に対して内側の配列も再調整する必要があります

于 2013-05-07T06:20:54.103 に答える
0

私はこの障害にぶつかりながら、この質問に出くわしました。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分くらいで書いたので保証はありません。ただし、使用したり拡張したりしたい場合は、お気軽に。誰かがこのようなコードをすでにここに持っていると思っていたでしょうが、明らかにそうではありません。それでは、仲間のギアヘッドに行きましょう。

于 2014-01-09T07:30:52.450 に答える