Как я могу "ReDim сохранить" 2D-массив в Excel 2007 VBA, чтобы я мог добавлять в массив строки, а не столбцы?

8 user392520 [2010-10-22 02:09:00]

Я работаю с динамическим массивом в Excel VBA. Количество столбцов (m) фиксировано, однако я не знаю, сколько строк (n) потребуется.

В справочных документах указано, что ReDim Preserve myArray (n, m) позволяет мне делать m больше, но не n. Однако мне нужно увеличить количество строк (n), сохраняя мои данные, а не столбцы (m)!

Например, у меня может быть массив (5,20), который я хотел бы расширить до (10,20), сохранив мои данные.

Кажется, что если бы был какой-то способ транспонировать мой массив, сделайте резервную копию ReDim, чтобы расширить количество "столбцов", а затем повторно транспонировать мой массив, я мог бы выполнить то, что хочу.

Это правильный способ сделать это? Если да, то как я могу это сделать?

Есть ли лучший способ выполнить то, что я хочу?

vba excel


8 ответов


0 Решение user392520 [2010-10-22 02:39:00]

Решил мой собственный вопрос; вот как я обошел свою проблему. Я создал временный массив, скопировал содержимое myArray во временный массив, изменил размер myArray, а затем скопировал содержимое из массива temp в myArray.

tempArray = myArray
ReDim myArray(1 To (UBound(myArray()) * 2), 1 To m)
For i = 1 To n
     For j = 1 To m
          myArray(i, j) = tempArray(i, j)
     Next j
Next i

Если кто-то может предложить более эффективный способ сделать это, я бы хотел его услышать.


12 jtolle [2010-10-22 03:49:00]

Один из способов сделать то, что вы хотите, - это использовать 1-D массив, содержащий 1-D массивы вместо 2-мерного массива. Затем вы можете ReDim сохранить внешний массив, который вы хотите. Если вы возвращаете внешний массив из функции, Excel будет делать все правильно и принуждать его к 2-мерному массиву.

Например, приведенная ниже функция вернет массив 3x2 в ячейки, из которых он вызвал:

Public Function nested()
    Dim outer
    outer = Array(Array(1, 2), Array(3, 4))

    ReDim Preserve outer(1 To 3)

    outer(3) = Array(5, 6)

    nested = outer
End Function

Мой ответ на эти вопросы также может быть вам полезен: Пропустить многомерный массив в Excel UDF в VBA и Вставка VBA 3-мерный массив в листе

Конечно, если вы не возвращаете это из UDF, вам придется его принуждать. Легкий способ сделать это без написания кода цикла:

Dim coerced
coerced = Application.Index(outer, 0, 0)

Это просто вызывает встроенную функцию INDEX в Excel, а нули означают, что вы хотите вернуть все свои строки и все ваши столбцы. Excel принудительно объединит ваш 1-мерный массив 1-D массивов в 2-мерный массив. (Предостережение: существуют ограничения по размеру, но они намного больше, чем 10x20.)


5 Nikolay Ivanov [2012-11-19 15:34:00]

Если вы разработчик - в чем разница между строками и столбцами? Использование массива (N, 2) (если у вас есть 2 столбца) совпадает с массивом (2, N), для которого вы можете

ReDim Preserve arr(1 to 2, 1 to N+1). 

И разница для вас (как разработчика) заключается в том, чтобы поместить переменную из цикла на второе место вместо первого:

N = ubound(arr)
FOR i=1 to N
    GetColumn1Value = arr(1, i)
    GetColumn2Value = arr(2, i)
NEXT i

Или вы хотите это:

N = ubound(arr)
FOR i=1 to N
    GetColumn1Value = arr(i, 1)
    GetColumn2Value = arr(i, 2)
NEXT i

В чем разница?


4 user2307527 [2013-05-23 14:56:00]

Один из способов, как вы могли бы это осознать, - это двойная транспозиция с изменением количества столбцов между ними. Однако это будет работать только для двумерных массивов. Это делается следующим образом:

' Adding one row is done by a double transposing and adding a column in between.
' (Excel VBA does not allow to change the size of the non-last dimension of a
' multidimensional array.)
myArray = Application.Transpose(myArray)
ReDim Preserve myArray(1 To m, 1 To n + 1)
myArray= Application.Transpose(myArray)

Конечно, m и n можно вывести следующим образом:

m = UBound(myArray, 1)
n = UBound(myArray, 2)

Таким образом, вы используете встроенную функцию транспонирования самого Excel. Как упоминалось в комментариях кода, это не будет работать для матриц более высокого порядка.


2 Earl [2011-11-02 03:09:00]

Слово "транспонировать" сразу бросается в глаза. Вы можете просто вводить данные в 2D-массив, переворачивая столбцы и строки (т.е. Транспонировать), эффективно позволяя вам делать n (теперь количество столбцов, но сохраняя значения строк) больше, когда вам нужно.

Чтобы ссылаться на значения, скажем, в двойном цикле, обменивайте индексы вокруг. Например. скорее перейдите от я = 1 к n и j = 1 к m, где вы ссылаетесь на значение (i, j), используйте я = от 1 до m и от j = 1 до n.


0 Stan Rogers [2010-10-22 02:21:00]

Нет способа определить количество элементов в первом измерении? Облом. Для двумерного массива с фиксированным вторым измерением вы можете захотеть сделать его массивом типов ( "structs" на других языках). Это позволит вам использовать Redim Preserve и по-прежнему оставляет вас разумным способом добавления и доступа к значениям, хотя теперь вы будете обращаться ко второму измерению как к именованным членам типа, а не к значениям индекса.


0 Dyrner [2013-06-13 23:57:00]

Массив с двумя размерами, где число столбцов фиксировано и число строк динамическое, можно создать следующим образом:

Sub test2DimArray()
Dim Arr2D() As String
Dim NumberOfCol As Long
Dim I As Long, J As Long, x As Long
Dim tmpValue As String, tmpValue2 As String, tmpValue3 As String

NumberOfCol = 3
J = 1
Debug.Print "Run " & Now()
Debug.Print "Sheet content"
Debug.Print "Row   col1     col2     col3"

For I = 1 To 10
tmpValue = Cells(I, 1).Value
tmpValue2 = Cells(I, 2).Value
tmpValue3 = Cells(I, 3).Value
Debug.Print I & " =    " & tmpValue & "     " & tmpValue2 & "     " & tmpValue3
    If Len(tmpValue) > 0 Then
        ReDim Preserve Arr2D(NumberOfCol, 1 To J)
        Arr2D(1, J) = tmpValue
        Arr2D(2, J) = tmpValue2
        Arr2D(3, J) = tmpValue3
        J = J + 1
    End If
Next

'check array values
Debug.Print vbLf; "arr2d content"
Debug.Print "Row   col1     col2     col3"

For x = LBound(Arr2D, 2) To UBound(Arr2D, 2)
Debug.Print x & " =   " & Arr2D(1, x) & "        " & Arr2D(2, x) & "        " & Arr2D(3, x)
Next

Debug.Print "========================="
End Sub

TempValue, прочитанный из ячеек A1: A10, если в ячейке Ax есть значение, он удаляет массив с +1 и добавляет Tempvalue в массив col1, добавляет содержимое в Bx в массив col2 и содержимое в Cx в массив col3. Если длина значения Ax равна 0, она ничего не добавляет к массиву.

Debug.print показывает результаты в "непосредственном окне" в редакторе VB.

Без тестовых линий и добавления динамического диапазона данных код может быть:

Sub my2DimArray()
Dim Arr2D() As String
Dim NumberOfCol As Long, NumberOfRow As Long
Dim FirstCol As Long, FirstRow As Long, LastCol As Long, LastRow As Long
Dim I As Long, J As Long, X As Long
Dim tmpValue As String, tmpValue2 As String, tmpValue3 As String

'if cells with values start in A1
With ActiveSheet.UsedRange
    NumberOfCol = .Columns.Count
    NumberOfRow = .Rows.Count
End With

'if cells with values starts elsewhere
With ActiveSheet.UsedRange
    FirstCol = .Column
    FirstRow = .Row
    LastCol = .Column + .Columns.Count - 1
    LastRow = .Row + .Rows.Count - 1
End With

J = 1

For I = 1 To NumberOfRow 'or For I = FirstRow to LastRow
tmpValue = Cells(I, 1).Value 'or tmpValue = Cells(I, FirstCol).Value
    If Len(tmpValue) > 0 Then
        ReDim Preserve Arr2D(NumberOfCol, 1 To J)
            For X = 1 To NumberOfCol 'or For X = FirstCol to LastCol
                Arr2D(X, J) = Cells(I, X).Value
            Next X
        J = J + 1
    End If
Next I

End Sub

0 sifar786 [2013-06-08 11:35:00]

coercing или Slicing, похоже, не работают с Index (или Match (Index) (если я хочу фильтровать массив (без циклов) на основе нескольких критериев, когда размер данных превышает 2 × 16 строк (~ 92000 строки).

Run-Time error '13':

Type Mismatch

Transpose не работает с большими наборами записей, и поэтому двойная Transpose не работает. не существует, чтобы фильтровать массив и захватывать данные, не прибегая к нескольким циклам?

Я думаю о попытке использования словаря или ADO с помощью Excel.