2013-05-04 10 views
14

Ich verwende VB6 und ich brauche ein ReDim Konserve zu einem multidimensionalen Array zu tun:ReDim Konserve zu einem multidimensionalen Array in Visual Basic 6

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) 

Immer, wenn ich es tun, wie ich geschrieben habe es, bekomme ich folgende Fehlermeldung:

runtime error 9: subscript out of range

Weil ich nur die letzte Array-Dimension ändern kann, auch in meiner Aufgabe, die ich habe das ganze Array (2 Dimensionen in meinem Beispiel) ändern!

Gibt es eine Problemumgehung oder eine andere Lösung dafür?

Antwort

2

in Bezug auf diese:

"in my task I have to change the whole array (2 dimensions"

einfach eine gezackte Array verwenden (dh ein Array von Arrays von Werten). Dann können Sie die Abmessungen beliebig ändern. Ein bisschen mehr Arbeit vielleicht, aber eine Lösung.

+0

VB6 bietet keine Unterstützung für Arrays von Arrays –

+3

@EuroMicelli ja es tut. Sie können ein 1-D-Array mit Varianten haben, und die Varianten können Arrays enthalten. – MarkJ

6

Wie Sie richtig darauf hin, kann man ReDim Preserve nur die letzte Dimension eines Arrays (ReDim Statement auf MSDN):

If you use the Preserve keyword, you can resize only the last array dimension and you can't change the number of dimensions at all. For example, if your array has only one dimension, you can resize that dimension because it is the last and only dimension. However, if your array has two or more dimensions, you can change the size of only the last dimension and still preserve the contents of the array

Daher ist die erste Frage zu entscheiden, ob 2-dimensionaler Array ist die besten Daten Struktur für den Job. Vielleicht, 1-dimensionale Array ist eine bessere Passform, wie Sie ReDim Preserve tun müssen?

Eine andere Möglichkeit ist gezackte Array wie Pieter Geerkens's suggestion zu verwenden. Es gibt keine direkte Unterstützung für gezackte Arrays in VB6. Eine Möglichkeit, "Arrays von Arrays" in VB6 zu programmieren, besteht darin, ein Array von Variant zu deklarieren und jedes Element zu einem Array des gewünschten Typs zu machen (String in Ihrem Fall). Der Democode ist unten.

Eine weitere Option ist es, Preserve Teil auf eigene Faust zu implementieren. Dazu müssen Sie eine Kopie der zu sichernden Daten erstellen und dann das redimensionierte Array damit füllen.

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 
+0

Ich habe Angst, wenn in der Funktion "ResizeMatrix" in der Zeile "StringArray = a (i)" ein "type mismatch" -Fehler auftritt. Wenn ich den Bereich der alten Matrix überschreite, ist a (i) vom Typ Variant/Empty. Kann es an etwas vom Typ String() übergeben werden? –

0

Sie können einen benutzerdefinierten Typ verwenden, der ein Array von Strings enthält, das das innere Array ist. Dann können Sie ein Array dieses benutzerdefinierten Typs als äußeres Array verwenden.

Werfen Sie einen Blick auf die folgenden Testprojekt:

'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 

Führen Sie das Projekt, und klicken Sie auf die Form, den Inhalt der Felder angezeigt werden soll.

Klicken Sie auf Command1, um das äußere Array zu vergrößern, und klicken Sie erneut auf das Formular, um die Ergebnisse anzuzeigen.

Klicken Sie auf Command2, um ein inneres Array zu vergrößern, und klicken Sie erneut auf das Formular, um die Ergebnisse anzuzeigen.

Vorsicht aber: wenn Sie das äußere Array REDIM, können Sie auch die inneren Arrays für alle neuen Elemente der äußeren Anordnung

0

ich auf diese Frage gestolpert, während Schlagen diese Straße blockieren mich REDIM müssen. Am Ende habe ich ein Stück Code geschrieben, das sehr schnell mit diesem ReDim Preserve auf einem neu dimensionierten Array (erste oder letzte Dimension) zu tun hat. Vielleicht hilft es anderen, die das gleiche Problem haben.

Also für die Verwendung, nehmen wir an, Sie haben Ihr Array ursprünglich als MyArray(3,5), und Sie möchten die Abmessungen (zuerst auch!) Größer machen, sagen wir einfach MyArray(10,20). Sie wären es gewohnt, so etwas richtig zu machen?

Aber leider gibt das einen Fehler zurück, weil Sie versucht haben, die Größe der ersten Dimension zu ändern. Also mit meiner Funktion, würden Sie nur so etwas wie dies stattdessen tun:

MyArray = ReDimPreserve(MyArray,10,20) 

nun das Array größer ist, und die Daten erhalten bleiben. Ihr ReDim Preserve für ein Multi-Dimension-Array ist abgeschlossen. :)

Und last but not least, die wunderbare Funktion: 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 

ich dies wie 20 Minuten schrieb, so gibt es keine Garantien. Aber wenn Sie es verwenden oder erweitern möchten, fühlen Sie sich frei. Ich hätte gedacht, dass jemand hier oben schon einen Code wie diesen gehabt hätte, offensichtlich nicht. Also, hier gehts mit anderen Gearheads.

0

Dies ist kompakter und respektieren die ursprüngliche erste Position in Array und verwenden Sie einfach die Anfangsbindung, um alten Wert hinzuzufügen.

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 

Ich nenne diese Unter mit dieser Zeile der ersten Dimension, um die Größe

ReDimPreserve arr2, UBound(arr2, 1) + 1, UBound(arr2, 2) 

Sie können einen anderen Test hinzufügen, um zu überprüfen, ob die Anfangsgröße als neuer Array nicht obere ist. In meinem Fall ist es nicht notwendig

4

Da VB6 ist sehr ähnlich zu VBA, ich denke, ich könnte eine Lösung haben, die nicht so viel Code zu ReDim ein 2-dimensionales Array - mit Transpose.

Die Lösung (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) 

Was von OP Frage anders: die untere Grenze von arrCity Array nicht 0 ist, aber 1. Dies ist, um Job es ist, zu lassen Application.Transpose tun.

Ich denke, Sie sollten die Transpose Methode in VB6 haben.

+1

Nein. Transpose ist eine Methode des Excel-Anwendungsobjekts (in Wirklichkeit eine Verknüpfung zu Application.WorksheetFunction.Transpose). In VB6 gibt es nichts Vergleichbares. Und in VBA muss man bei der Verwendung von Transpose vorsichtig sein, da es zwei wesentliche Einschränkungen hat. Wenn das Array mehr als 65536 Elemente enthält, wird es fehlschlagen. Wenn die Länge eines Elements länger als 256 Zeichen ist, schlägt es fehl. Wenn keine von beiden ein Problem darstellt, konvertiert Transpose den Rang eines Array-Forms 1D in 2D oder umgekehrt. –

+0

Kann ich Sie fragen, wo/wie haben Sie gelernt, dass Application.Transpose eine * Verknüpfung * zu Application.WorksheetFunction.Transpose ist? – ZygD

1

Ich habe nicht jede einzelne dieser Antworten getestet, aber Sie müssen keine komplizierten Funktionen verwenden, um dies zu erreichen. Es ist so viel einfacher als das! Mein Code unten funktioniert in jeder Office-VBA-Anwendung (Word, Access, Excel, Outlook usw.) und ist sehr einfach. Hoffe, das hilft:

''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) 
0

Ich weiß, das ist ein bisschen alt, aber ich denke, es könnte eine viel einfachere Lösung, die keine zusätzliche Codierung erfordert:

Statt Transponieren, redimming und Umsetzung wieder, und wenn wir Sprechen Sie über ein zweidimensionales Array, warum speichern Sie nicht einfach die transponierten Werte. In diesem Fall erhöht redim preserve die rechte (zweite) Dimension von Anfang an. Oder mit anderen Worten, um es zu visualisieren, warum nicht in zwei Zeilen statt in zwei Spalten speichern, wenn nur die Anzahl der Spalten mit redim preserve erhöht werden kann.

die Indizes wäre dann 00-01, 01-11, 02-12, 03-13, 04-14, 05-15 ... 0 25-1 25 usw. statt 00-01, 10-11 , 20-21, 30-31, 40-41 und so weiter.

Solange es nur eine Dimension gibt, die redimed-conserved werden muss, würde der Ansatz immer noch funktionieren: einfach diese Dimension zuletzt setzen.

Da nur die zweite (oder letzte) Dimension beim Redimmen beibehalten werden kann, könnte man vielleicht argumentieren, dass Arrays so verwendet werden sollten. Ich habe diese Lösung nirgendwo gesehen, vielleicht übersehen ich etwas?

(Veröffentlicht früher auf ähnliche Frage in Bezug auf zwei Dimensionen erweitert Antwort hier für weitere Dimensionen)