2013-05-04 12 views
14

sto utilizzando VB6 e ho bisogno di fare un ReDim Preserve a un array multi-dimensionale:ReDim Preserve ad un array multi-dimensionale 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) 

Ogni volta che lo faccio, come ho scritto esso, ottengo il seguente errore:

runtime error 9: subscript out of range

Perché posso cambiare solo l'ultima dimensione dell'array, bene nel mio compito devo cambiare l'intero array (2 dimensioni nel mio esempio)!

C'è qualche soluzione alternativa o un'altra soluzione per questo?

risposta

2

In riferimento a questa:

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

semplicemente utilizzare un matrice irregolare (cioè un array di array di valori). Quindi puoi cambiare le dimensioni come preferisci. Forse un po 'più di lavoro, ma una soluzione.

+0

VB6 non supporta array di array –

+3

@EuroMicelli sì lo fa. Puoi avere una serie di varianti 1-D e le varianti possono contenere array. – MarkJ

6

Come lei giustamente notare, si può ReDim Preserve solo l'ultima dimensione di un array (ReDim Statement su 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

Quindi, la prima questione da decidere è se matrice a 2 dimensioni è il dato migliore struttura per il lavoro. Forse l'array 1-dimensionale è più adatto in quanto devi fare ReDim Preserve?

Un altro modo è utilizzare la matrice seghettata come da Pieter Geerkens's suggestion. Non esiste un supporto diretto per gli array frastagliati in VB6. Un modo per codificare "array di matrici" in VB6 è dichiarare un array di Variant e rendere ogni elemento un array di tipo desiderato (String nel tuo caso). Il codice demo è sotto.

Un'altra opzione è quella di implementare la parte Preserve da soli. Per questo è necessario creare una copia dei dati da conservare e quindi riempire l'array ridimensionato con esso.

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

Ho paura di un errore di "mancata corrispondenza del tipo" nella riga "StringArray = a (i)" nella funzione ResizeMatrix. Se vado oltre l'intervallo della vecchia matrice, un (i) è di tipo Variant/Empty. Può essere passato a qualcosa del tipo String()? –

0

È possibile utilizzare un tipo definito dall'utente contenente un array di stringhe che costituirà l'array interno. Quindi è possibile utilizzare un array di questo tipo definito dall'utente come array esterno.

Date un'occhiata al seguente progetto di test:

'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 

eseguire il progetto e fare clic sul form per visualizzare il contenuto delle matrici.

Fare clic su Command1 per ingrandire l'array esterno, quindi fare nuovamente clic sul modulo per visualizzare i risultati.

Fare clic su Command2 per ingrandire un array interno e fare nuovamente clic sul modulo per visualizzare i risultati.

Attenzione però: quando si ReDim la matrice esterna, si hanno anche per REDIM le matrici interne per tutti i nuovi elementi della matrice esterna

0

mi sono imbattuto in questa domanda, mentre colpire questa strada bloccare me stesso. Ho finito per scrivere un pezzo di codice molto veloce per gestire questo ReDim Preserve su un array di nuova dimensione (prima o ultima dimensione). Forse aiuterà gli altri che affrontano lo stesso problema.

Quindi, per l'utilizzo, diciamo che l'array è stato impostato originariamente come MyArray(3,5) e che si desidera aumentare le dimensioni (innanzitutto!), Diciamo semplicemente a MyArray(10,20). Saresti abituato a fare qualcosa del genere giusto?

ReDim Preserve MyArray(10,20) '<-- Returns Error 

Ma purtroppo restituisce un errore perché si è tentato di modificare la dimensione della prima dimensione. Così con la mia funzione, si sarebbe solo fare qualcosa di simile, invece:

MyArray = ReDimPreserve(MyArray,10,20) 

Ora la matrice è più grande, ei dati vengono conservati. Il tuo ReDim Preserve per un array a più dimensioni è completo. :)

E, ultimo ma non meno importante, la funzione miracolosa: 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 

ho scritto questo come 20 minuti, quindi non ci sono garanzie. Ma se vuoi usarlo o estenderlo, sentiti libero. Avrei pensato che qualcuno avrebbe già avuto un codice come questo qui, beh apparentemente no. Quindi qui vai a fare i colleghi.

0

Questo è più compatto e rispetta la prima posizione iniziale nell'array e usa semplicemente il limite iniziale per aggiungere il vecchio valore.

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 

Io chiamo questo sub con questa linea per ridimensionare la prima dimensione

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

È possibile aggiungere un altro test per verificare se la dimensione iniziale non è superiore a nuovo array. Nel mio caso non è necessario

4

Dal momento che VB6 è molto simile a VBA, penso che potrei avere una soluzione che non richiede questo codice a ReDim un array bidimensionale - utilizzando Transpose.

La soluzione (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) 

Ciò che è diverso dalla domanda di OP: il limite inferiore di arrCity array non è 0, ma 1. Questo è per far Application.Transpose fare il suo lavoro.

Penso che dovresti avere il metodo Transpose in VB6.

+1

No. Transpose è un metodo dell'oggetto Applicazione Excel (che in realtà è un collegamento a Application.WorksheetFunction.Transpose). Non c'è nulla di simile in VB6. E in VBA, bisogna fare attenzione quando si utilizza Transpose in quanto ha due limitazioni significative. Se la matrice ha più di 65536 elementi, fallirà. In QUALSIASI lunghezza di un elemento supera i 256 caratteri, fallirà. Se nessuno di questi è un problema, Transpose convertirà bene il rango di un array da 1D a 2D o viceversa. –

+0

Posso chiederti dove/come hai appreso che Application.Transpose è una * scorciatoia * per Application.WorksheetFunction.Transpose? – ZygD

1

Non ho provato ognuna di queste risposte ma non è necessario utilizzare complicate funzioni per ottenere questo risultato. È molto più facile di così! Il mio codice di seguito funzionerà in qualsiasi applicazione VBA per ufficio (Word, Access, Excel, Outlook, ecc.) Ed è molto semplice. Spero che questo aiuta:

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

So che questo è un po 'vecchio, ma penso che ci potrebbe essere una soluzione molto più semplice che non richiede alcun codice aggiuntivo:

Invece di trasposizione, redimming e recepimento di nuovo, e se noi parlare di un array bidimensionale, perché non memorizzare i valori trasposti per cominciare. In tal caso, redim preservare aumenta effettivamente la giusta (seconda) dimensione dall'inizio. In altre parole, per visualizzarlo, perché non archiviare in due righe anziché in due colonne se è possibile aumentare il numero di colonne con la conservazione redim.

gli indici sarebbero 00-01, 01-11, 02-12, 03-13, 04-14, 05-15 ... 0 25-1 25 eccetera anziché 00-01, 10-11 , 20-21, 30-31, 40-41 ecc.

Finché c'è solo una dimensione che deve essere ridimensionata, l'approccio continua a funzionare: basta mettere quella dimensione per ultima.

Poiché solo la seconda (o ultima) dimensione può essere conservata durante il risanamento, si potrebbe forse sostenere che questo è il modo in cui si suppone che gli array vengano utilizzati per iniziare. Non ho visto questa soluzione da nessuna parte, quindi forse sto trascurando qualcosa?

(Pubblicato in precedenza domanda simile per quanto riguarda due dimensioni, estesa risposta qui per maggiori dimensioni)

Problemi correlati