Как я могу «ReDim Preserve» 2D-массив в Excel 2007 VBA, чтобы я мог добавить строки, а не столбцы, в массив? - PullRequest
9 голосов
/ 22 октября 2010

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

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

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

Похоже, что если бы был какой-то способ транспонировать мой массив, сделайте ReDim Preserve, чтобы увеличить количество «столбцов», затем переставьте мой массив, я мог бы выполнить то, что я хочу.1008 * Это правильный способ сделать это?Если так, как я могу это сделать?

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

Ответы [ 8 ]

12 голосов
/ 22 октября 2010

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

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

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)

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

6 голосов
/ 23 мая 2013

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

' 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. Как упоминалось в комментариях к коду, это не будет работать для матриц более высокого порядка.

5 голосов
/ 19 ноября 2012

Если вы разработчик - в чем разница между строками и столбцами?Использование массива (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

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

2 голосов
/ 02 ноября 2011

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

0 голосов
/ 14 июня 2013

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

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 голосов
/ 08 июня 2013

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

Run-Time error '13':

Type Mismatch

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

Я думаю попробовать словарь или ADO с Excel.

0 голосов
/ 22 октября 2010

решил мой собственный вопрос; вот как я обошёл мою проблему. Я создал временный массив, скопировал содержимое myArray во временный массив, изменил размер myArray, затем скопировал содержимое обратно из временного массива в 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

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

0 голосов
/ 22 октября 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...