Excel VBA - присвояването на масив променя LBound и UBound

Имам някои много големи набори от данни в Excel, които трябва да анализирам - и да го направя в масив е по-бързо, отколкото да преглеждам данните в работния лист. Зареждането на всички данни в масив причинява проблеми с паметта (наборите от данни СА толкова големи), така че планирам да заредя подмножества от данни в масив, да ги обработя, след което да заредя друго подмножество. Надявах се да използвам "функцията" на масива за дефиниране на LBound и UBound, за да ми помогне да следя къде се намирам в работния лист. Но намирам, че присвояването на стойностите на работния лист към масива променя границите. Следният код демонстрира проблема...

    Sub myTest3()
    Dim myRange As Range
    Dim myArray As Variant
    Dim myOffset As Long

        myOffset = 10
        Set myRange = Worksheets("RawData").Range("A1").CurrentRegion
        ReDim myArray(myOffset To myRange.Rows.Count, myRange.Columns.Count)
        MsgBox LBound(myArray, 1) & " to " & UBound(myArray)

        Set myRange = myRange.Offset(myOffset, 0).Resize(myRange.Rows.Count - myOffset, myRange.Columns.Count)

        myArray = myRange.Value2

        MsgBox LBound(myArray, 1) & " to " & UBound(myArray)

    End Sub

Първият MsgBox ми дава "10 до 10931". Вторият MsgBox ми дава "1 до 10921".

Някакви идеи за поддържане на границите на масива, както ги дефинирах първоначално? Знам, че преминаването през работния лист, за да се направи задачата, ще го направи, но ще бъде бавно.

Благодаря предварително.


person OldUgly    schedule 20.10.2013    source източник
comment
Присвояването на масив от диапазон с помощта на .Value винаги създава масив, базиран на 1. Ако имате нужда от различно поведение, тогава ще трябва да попълните масива с помощта на цикъл.   -  person Tim Williams    schedule 21.10.2013
comment
Оцвети ме тъжно. Благодаря Тим. Предполагам, че ще трябва да преструктурирам кода си, за да мога да следя местоположението си с помощта на цикъл.   -  person OldUgly    schedule 21.10.2013
comment
Проблемът е, че използвате оператор ReDim, за да декларирате отново масива с долна граница от 10, тук: ReDim myArray(myOffset to .... Какво точно се опитвате да направите с променливата myOffset? Мисля, че това е причината.   -  person David Zemens    schedule 21.10.2013
comment
Всъщност, Дейвид, това е функцията, от която се опитвам да се възползвам. Във VBA можете да зададете LBound да бъде каквото искате. В моя проект (не непременно примерния код) се надявах да присвоя долната и горната граница на масива, за да съответстват на редовете в работния лист, от който бяха данните. Това би ми позволило да го върна на същите места след съответните промени. Мисля, че коментарът на Тим е това ... когато се присвоява масив от диапазон, изглежда, че автоматично променя масива с LBound = 1.   -  person OldUgly    schedule 21.10.2013
comment
@OldUgly Мисля, че this може да ви помогне.   -  person    schedule 21.10.2013


Отговори (1)


Excel VBA не работи както искате в тази ситуация. Когато изпълните myArray = myRange.Value2, оригиналното съдържание на myArray беше заменено. Масивът Redimmed беше изхвърлен. Excel/VBA не разглежда целта, а я замества или, вероятно по-правилно, създава нов масив и кара променливата myaArray да сочи към това.

Така че ще ви трябва малко повече код, за да стигнете там, където искате да бъдете. Бих помислил да поставя кода за грабване на следващата част в отделна функция и да водя счетоводството там:

Function ChunkAtOffset(rng As Range, rowsInChunk As Long, colsInChunk As Long, offsetRows As Long) As Variant
' Note: doesn't cater for the case where there are fewer than 'offsetRows' in the target    
Dim arr As Variant, result As Variant
Dim r As Long, c As Long

    arr = rng.offset(offsetRows).Resize(rowsInChunk, colsInChunk).Value2

    ReDim result(offsetRows To offsetRows + rowsInChunk - 1, 1 To colsInChunk)

    For r = 1 To rowsInChunk
        For c = 1 To colsInChunk
            result(offsetRows - 1 + r, c) = arr(r, c)
        Next
    Next

    ChunkAtOffset = result

End Function

Ако стартирам това:

Sub myTest4()

    Dim curReg As Range, ary As Variant, offset As Long
    With Range("A1")
        Set curReg = .CurrentRegion
        Do
            ary = ChunkAtOffset(.CurrentRegion, 10, .CurrentRegion.Columns.Count, offset)
            Debug.Print LBound(ary, 1) & " to " & UBound(ary)
            offset = offset + 10
        Loop Until offset >= .CurrentRegion.Rows.Count
    End With

End Sub

... сега разбирам това:

0 to 9
10 to 19
20 to 29
person Mike Woodhouse    schedule 21.10.2013
comment
това изглежда добре. Накрая направих нещо подобно. Благодаря за помощта на всички. - person OldUgly; 22.10.2013