2013-05-04 1 views
14

내가 사용 VB6에서 다차원 배열에 보존하고 나는 ReDim을 다차원 배열에 보존 할 필요가 : 내가 쓴 나는 그것을 할 때마다ReDim을 비주얼 베이직 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) 

그것은, 나는 다음과 같은 오류가 발생합니다 :

runtime error 9: subscript out of range

난 단지 내가 전체 배열 (내 예제에서 2 차원)을 변경해야 할 내 작업에서 잘 마지막 배열 차원을 변경할 수 있기 때문에!

해결 방법이나 다른 해결책이 있습니까? 이에 관해서

답변

2

:

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

그냥 가변 배열 (값의 배열, 즉 배열)를 사용합니다. 그런 다음 원하는대로 치수를 변경할 수 있습니다. 아마도 조금 더 효과가있을 수 있지만 해결책이됩니다.

+0

VB6는 –

+3

@EuroMicelli이 예는 않습니다 배열의 배열을 지원하지 않습니다. 변형의 1 차원 배열을 가질 수 있으며 변형은 배열을 포함 할 수 있습니다. – MarkJ

6

올바르게 지적으로, 한 수 배열 (MSDN에 ReDim Statement)의 ReDim Preserve 마지막 차원 :

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

따라서, 결정하는 첫 번째 문제는 2 차원 배열이 가장 좋은 데이터가 있는지 여부입니다 구조. 어쩌면 1 차원 배열이 ReDim Preserve해야 할 때 더 적합할까요?

또 다른 방법은 Pieter Geerkens's suggestion에 따라 들쭉날쭉 한 배열을 사용하는 것입니다. VB6에서는 들쭉날쭉 한 배열을 직접 지원하지 않습니다. VB6에서 "배열 배열"을 코딩하는 한 가지 방법은 배열을 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 
+0

ResizeMatrix 함수에서 "StringArray = a (i)"줄에 "형식이 일치하지 않습니다"오류가 발생합니다. 내가 오래된 행렬의 범위를 벗어나면, a (i)는 Variant/Empty 유형입니다. 그것은 뭔가 String() 형식으로 전달할 수 있습니까? –

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를 클릭하고 양식을 다시 클릭하여 결과를 표시하십시오.

하지만주의 : 당신이 외부 배열을 REDIM 때, 당신은 또한이 도로 나 자신을 차단 치는 동안이 질문을 우연히 발견 외부 배열

0

의 모든 새로운 요소의 내부 배열을 ReDim을해야합니다. 새로운 크기의 배열 (첫 번째 또는 마지막 차원)에이 코드를 처리하기 위해 코드 조각을 작성했습니다. 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 분 같은이 쓴, 그래서 보장은 없다. 그러나 그것을 사용하거나 확장하고 싶다면 자유롭게 생각하십시오. 나는 누군가가 이미 이런 코드를 이미 가지고 있다고 생각했을 것이다. 그래서 여기에 동료 gearheads 이동하십시오.

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) 

의 크기를 조정하려면이 라인이 하위를 호출합니다. 제 경우에는 필요하지 않습니다

4

VB6은 VBA와 매우 유사하므로 ReDimTranspose을 사용하는 많은 코드가 필요하지는 않습니다. 무엇 OP의 질문 다른

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) 

:

솔루션 (VBA)는 낮은 arrCity 배열의 경계 것은 0이 아니라 1이 Application.Transpose 그것이 직업 할 수 있도록하기 위해서입니다.

VB6에서는 Transpose 메서드가 있어야한다고 생각합니다.

+1

번호 Transpose는 Excel Application 개체의 메서드입니다 (실제로 Application.WorksheetFunction.Transpose의 바로 가기 임). VB6에는 그런 것이 없습니다. 그리고 VBA에서는 Transpose를 사용할 때 두 가지 중요한 제한 사항이 있으므로주의해야합니다. 배열에 65536 개가 넘는 요소가 있으면 실패합니다. ANY 요소의 길이가 256자를 넘으면 실패합니다. 이들 중 어느 것도 문제가되지 않는다면, Transpose는 배열 형식 1D의 순위를 2D로 또는 그 반대로 잘 변환 할 것입니다. –

+0

Application.Transpose가 Application.WorksheetFunction.Transpose의 * 단축키 *라는 것을 어디에서 어떻게 알게 되었습니까? – ZygD

1

나는이 모든 답변을 하나씩 테스트하지는 않았지만이를 수행하기 위해 복잡한 기능을 사용할 필요가 없습니다. 그것보다 훨씬 쉽습니다! 아래의 코드는 모든 Office 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) 
0

하지만 추가적인 코딩이 필요없는 매우 간단한 해결책이있을 수 있습니다 생각 : 희망이 도움이

대신 이조, redimming 다시 전치의, 우리의 경우 2 차원 배열에 대해 이야기하고, 왜 처음부터 바꿔 치기 값을 저장하는 것이 아닙니다. 이 경우 잔존 보존은 실제로 처음부터 오른쪽 (두 번째) 차원을 증가시킵니다. 즉, 시각화하기 위해 두 개의 열 대신에 두 개의 행을 저장하는 것이 좋습니다. 열의 nr 만이 redim 보존으로 증가 할 수 있습니다.

인덱스가 00-01, 01-11, 02-12, 03-13, 04-14, 05-15 ... 0 25-1 25 대신 00-01, 10-11 대신에 , 20-21, 30-31, 40-41 등.

redimmed-preserved 할 필요가있는 차원이 하나 뿐인 한 접근법은 여전히 ​​유효합니다. 마지막으로 치수를 넣으십시오.

리디렉션하는 동안 두 번째 (또는 마지막) 차원 만 보존 할 수 있기 때문에 처음에는 배열을 사용하는 방법이라고 주장 할 수 있습니다. 어디서나이 솔루션을 보지 못했을 수도 있습니다. (자세한 치수는 여기에 대답을 확장 이전 두 가지 차원에 대한 비슷한 질문에 게시 됨,)