2008-10-17 4 views
1

제목이 언급했듯이 VBA 동적 배열이 0이 아닌 경우 여분의 요소가 나타나지 않도록하는 방법이 있습니까? 예를 들어VBA 동적 배열의 추가 요소를 방지하는 방법이 있습니까?

, 다음과 유사한 코드를 사용하여 :

While Cells(ndx, 1).Value <> vbNullString 
    ReDim Preserve data(1 To (UBound(data) + 1)) 
    ndx = ndx + 1 
Wend 

당신은 처리의 끝에 여분의 빈 배열 요소를 가지고 있습니다. 이 문제는 다음과 같이 제거 할 수 있습니다.

ReDim Preserve data(1 To (UBound(data) - 1)) 

이 문제를 해결하는 가장 좋은 방법은 아닌 것 같습니다.

이와 같이 처음부터 여분의 요소가 생성되는 것을 방지 할 수있는 방법이 있습니까? 루프의 내부에서 추가적인 논리를 필요로하지 않는 무언가가 바람직합니다.

답변

1

그래서이 문제가 실제로 발생하지 않도록하는 방법이없는 것처럼 보이는 것처럼 성가신 작은 문제로 밝혀졌습니다. 다른 사용자가 제공 한 답변을 바탕으로 다음과 같은 방법으로 문제를 해결했습니다.

Using a Collection -이 접근법은 데이터를 읽고 저장해야하는 상황에서 상당히 효과적이지만 사용자 정의 유형은 컬렉션과 함께 사용할 수 없습니다. 항목 키를 정의 할 수 있으면 두 개의 컬렉션을 상호 참조 할 때 사용할 수 있으므로 유용합니다. 그러나 VBA에는 제한 될 수있는 no way to get the list of keys in the Collection이 있습니다.

Reading an Excel Range into an Array - 또 다른 멋진 접근 방식이지만, 범위가 무엇인지 미리 알면 가장 잘 작동하는 것 같습니다. 범위를 알아 내야 만한다면 Collection 또는 더 작은 ReDim 배열을 사용하는 것이 더 쉬운 상황에 처할 수도 있습니다.

ReDim Preserve로 즉시 어레이 빌드 -이 작업은 상당히 간단한 작업이지만, 두 가지 문제가 있습니다. 하나는 Visual Basic에서 지정된 크기의 새 배열을 실제로 만들고 이전 배열을 복사 한 다음 이전 배열을 삭제하거나 Visual Basic .NET에서 가비지 수집기 용으로 해제하므로 값 비싼 작업이 될 수 있다는 것입니다. 따라서 매우 큰 배열로 작업하려는 경우 ReDim에 대한 호출을 최소화해야합니다.

또한 배열 시작 부분이나 비어있는 배열 끝에 여분의 요소가있는 질문과 유사한 상황이 발생할 수 있습니다. 이 문제를 해결하는 유일한 방법은 작업을 수행하기 전에 크기를 조정해야하는지 확인하거나 결과를 반환하기 전에 빈 요소를 삭제하는 것입니다.

1

Visual Basic 배열은 0부터 시작합니다. 그래도 Option Base 문을 사용하여 변경할 수 있습니다.

배열의 경우 추가 요소는 UBound() + 1이므로 UBound에서 올바른 번호를 이미 제공합니다. 배열에 5 개의 요소가있는 경우 UBound는 5가됩니다. 그러나 마지막 인덱스는 4이므로 ReDim에서 UBound로 +1 크기의 배열을 제공합니다.

배열은 어쨌든 (VBA에서는) 사용하기에 고통이며 ReDim Preserve은 새로운 고정 크기 배열에 대한 배열 복사 작업입니다. 가능하면 어디에서나 Collections를 사용하는 것이 좋습니다. 그들은 반복하기가 훨씬 쉬우 며 (For Each ... In ...) 요소 추가, 찾기 및 제거에 훨씬 효율적입니다.

' creation ' 
Dim anyValue as Variant 
Dim c as New Collection 

' and adding values ' 
c.Add anyValue, strKey 

' iteration ' 
For Each anyValue in c 
    Debug.Print anyValue 
Next c 

' count values ' 
Debug.Print c.Count 

' element deletion ' 
c.Delete strKey 

(당신은 추가 편안함에서 VBScript Scripting.Dictionary를 사용할 수 있지만 먼저 참조해야합니다.)

또한 단순히 서로의 내부에 배치하여 컬렉션의 여러 차원을 가질 수 있습니다 .

+0

감사 할 것입니다 필요한 경우이

Dim data() Dim i as Long ReDim data(-1 To -1) ' Empty array. We never use data(-1). For i = 0 To UBound(data) ... Next i 

같은 빈 배열을 정의하는 것, 내가 VBA와의 컬렉션에 대해 잊고 있었던 동적 배열보다 훨씬 더 잘 작동합니다. 그러나 컬렉션을 사용할 때 잔인 함이있을 때 이러한 추가 요소를 표시하지 않으려 고합니다. – rjzii

+0

추가 요소는 무엇입니까? 추가 요소는 없습니다. 컬렉션에 무언가를 추가해야 할 때 미리 크기를 선택할 필요가 없습니다 (생각한 경우). – Tomalak

+0

@Tomalak - 동적 배열에 ReDim Preserve를 사용할 때 컬렉션에 없습니다. – rjzii

3

ReDim Preserve은 상대적으로 비용이 많이 드는 작업이며 모든 반복마다 수행 할 작업이 아닙니다. ReDim 배열을 원하는 것보다 큰 상한 (아마도 청크)으로 설정 한 다음 배열을 끝내면 필요한 상한으로 줄이십시오.

또한 Excel 범위를 배열로 읽는 다른 방법을 조사 할 수 있습니다.

Dim a() 
    With Sheet1 
    a = .Range(.Range("A1"), .Range("A1").End(xlDown)).Value 
    End With 
    Debug.Print a(1, 1) 

: 매우 느린 자주

1

VB6입니다 반복하고 COM은 0-와의 혼합 사용 (1)를 기반 인덱싱 (배열은 당신이 옵션 자료로이를 변경하거나 그것들을 선언 할 때를 제외하고 0을 기반으로 명시 적으로).

COM 컬렉션은 일반적으로 이전 COM 개체 모델에서는 1 기반이지만 때로는 0 기반입니다.

희미한/재정의하십시오 데이터 (1 내지 N)은

희미한/재정의하십시오 데이터 (0 N-1) N 1 내지 인덱스 N 소자 어레이 N 0 내지 인덱스 N 요소의 어레이이다 (옵션베이스이면 0) -1

희미한/재정의하십시오 데이터 (N)는 N 0 내지 인덱스 N + 1 개 요소의 배열이다

마지막 경우는 가끔 혼란 한 데이터 (N은)는 일반적으로 N + 1 개 요소의 배열 인 데이터 (0 ~ N)를 의미합니다.

필자는 항상 배열을 (0에서 N-1로) 명시 적으로 선언하고 두 개 이상의 언어를 사용하는 개발자에게 더 익숙한 Option Base에 의존하지 않습니다.

VBA는 길이가 0 인 배열을 지원하지 않으므로 항상 하나 이상의 요소 (다차원 배열의 각 차원에 대해)가 있어야합니다. 따라서 선언 할 수있는 가장 작은 배열은 하나의 요소가있는 데이터 (0에서 0) 또는 데이터 (1에서 1)입니다. 대신

ReDim data(1 To 1)  
While Cells(ndx, 1).Value <> vbNullString  
    ReDim Preserve data(1 To (UBound(data) + 1))  
    ndx = ndx + 1 
Wend 

(및 호출의 효율성의 순간 고려 따로 ​​떠나 : 귀하의 경우

, 난 당신이 다음 루프를 통해 요소마다 추가, 하나 개의 요소를 가진 배열을 생성하는 의심 ReDim을 루프에서 보존), 당신은 사용한다 :

ReDim data(1 To 1)  
nStartIndex = ndx 
While Cells(ndx, 1).Value <> vbNullString  
    ' On the first iteration this does nothing because 
    ' the array already has one element 
    ReDim Preserve data(1 To ndx - nStartIndex + 1)  
    ndx = ndx + 1 
Wend 
0

을 부여, 그 있었다 나는 고전적인 VB6를 해봤 및 memeory이 역할을하면 내 VBA 경험, ... 배열 구문도 rustier 때문에 잠시 VB에서 1 ​​inst 인 기본 이외의 다른 점 이 구문은 또한 지정한 "크기"가 배열의 총 요소 수를 나타내는 것이 아니라 마지막으로 처리 할 수있는 인덱스를 나타냅니다.

1

이 질문이 있기 때문에 꽤 오랜 시간이 걸립니다. 그러나 오늘 같은 문제가 발생하여 다음과 같이 해결했습니다.

사용하지 않을 첫 번째 요소를 정의하여이를 수행하는 방법이 있습니다. 당신이 제로 기반의 배열을해야 할 경우 1 기반의 배열이

ReDim data(0 To 0) ' Empty array. We never use data(0). 

For i = 1 To UBound(data) 
    ... 
Next i 
관련 문제