“我怎么能?”;“雷迪姆保护区”;Excel 2007 VBA中的二维数组,以便我可以向数组中添加行而不是列?
我正在使用Excel VBA中的动态数组。列数(m)是固定的,但是,我不知道需要多少行(n) 帮助文档指出,ReDim Preserve myArray(n,m)允许我将m变大,但不能将n变大。但是,我需要增加行数(n),同时保留数据,而不是列数(m) 例如,我可能有一个(5,20)数组,我希望在保留数据的同时将其扩展为(10,20) 似乎如果有某种方法可以转置我的数组,执行ReDim Preserve以扩展“列”的数量,然后重新转置我的数组,我就可以完成我想要的 这是正确的方法吗?如果是,我该怎么做“我怎么能?”;“雷迪姆保护区”;Excel 2007 VBA中的二维数组,以便我可以向数组中添加行而不是列?,excel,vba,Excel,Vba,我正在使用Excel VBA中的动态数组。列数(m)是固定的,但是,我不知道需要多少行(n) 帮助文档指出,ReDim Preserve myArray(n,m)允许我将m变大,但不能将n变大。但是,我需要增加行数(n),同时保留数据,而不是列数(m) 例如,我可能有一个(5,20)数组,我希望在保留数据的同时将其扩展为(10,20) 似乎如果有某种方法可以转置我的数组,执行ReDim Preserve以扩展“列”的数量,然后重新转置我的数组,我就可以完成我想要的 这是正确的方法吗?如果是,我该
是否有更好的方法来实现我的目标?无法确定第一维度中的元素数量?真倒霉对于具有固定第二维度的二维数组,您可能需要考虑将其作为类型数组(其他语言中的“结构”)。这将允许您使用Redim Preserve,并且仍然为您提供了添加和访问值的合理方式,尽管您现在将以该类型的命名成员而不是is索引值的身份访问第二维度。解决了我自己的问题;这是我如何解决我的问题的。我创建了一个临时数组,将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
如果有人能提出一种更有效的方法,我很乐意听到。一种方法是使用包含一维数组的一维数组,而不是二维数组。然后,您可以根据需要重新定义并保留外部阵列。如果您从函数返回外部数组,Excel将做正确的事情并将其强制为二维数组 例如,下面的函数将向调用它的单元格返回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
我对这些问题的回答也可能对你有用:以及
当然,如果你不是从UDF返回这个,你必须自己强制它。在不编写循环代码的情况下执行此操作的简单方法是:
Dim coerced
coerced = Application.Index(outer, 0, 0)
这只是调用Excel的内置索引函数,零表示要返回所有行和列。Excel将自动将一维数组强制为二维数组。(注意:有一些尺寸限制,但它们比10x20大得多。)一想到“转置”这个词就立刻想到了。您可以通过翻转列和行(即转置)简单地将数据输入到二维数组中,从而在需要时有效地使n(现在是列数,但存储行值)变大
要引用这些值,比如在双循环中,交换索引。例如,如果参考值(i,j)从i=1到n,从j=1到m,使用i=1到m,从j=1到n。如果您是开发人员,行和列之间的区别是什么? 使用数组(N,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
有什么不同吗?解决这个问题的一种方法是通过改变列数进行双转置。但是,这仅适用于二维阵列。具体做法如下:
' 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 = UBound(myArray, 1)
n = UBound(myArray, 2)
当然,m
和n
可以推断如下:
' 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 = UBound(myArray, 1)
n = UBound(myArray, 2)
因此,您可以使用Excel本身的内置转置功能。正如代码注释中提到的,这对高阶矩阵不起作用。当数据跨度大于2^16行(~92000行)时,强制或切片似乎不适用于基于多个条件筛选数组(w/o循环)的索引(或匹配(索引) 转置不适用于大的记录集,因此双转置也不起作用。难道不存在过滤数组和获取数据而不诉诸多个循环的方法吗
我正在考虑使用Excel尝试字典方式或ADO。可以这样创建二维数组,其中列数固定,行数动态:
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
从单元格A1:A10读取TempValue,如果单元格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
我没有使用或尝试这个方法,因为这次我的解决方案足以满足我的需要。乍一看,这看起来确实是一种更优雅、更高效的方法来完成我想要的。谢谢。我很惊讶这有多快。16200行*14列=226000个值(2x转置,1x重拨)嗯,当我执行第一行代码时,我得到了一个类型不匹配错误。这必须在实际的工作表范围而不是二维数组变量上执行吗?-1:数组的每个redim都有两个嵌套的循环-一点也不好!如果有一个10000个元素的数组,会发生什么?好吧,区别是不需要同时更改这两个维度。或者我不知道哪个维度会受到影响。@Ister,如果使用“保留”关键字,则只能调整最后一个数组维度的大小,而不能更改维度的数量。该规则不仅适用于Office 2013及更高版本(如上面的链接所示),而且适用于从2003年开始的任何Office(我没有使用旧版本的经验)。我完全意识到这一局限性。我的意思是,我不能每次都简单地转置数组,也不能满足于改变