如何调整循环中的数组?
我想在Excel中返回一个数组。 我一直在使用这个网站作为参考: http : //www.cpearson.com/excel/returningarraysfromvba.aspx
所以我从这个基本的示例脚本开始,它返回一个值的matrix(从上面的网站获取):
Function Test() As Variant Dim V() As Variant Dim N As Long Dim R As Long Dim C As Long ReDim V(1 To 3, 1 To 4) For R = 1 To 3 For C = 1 To 4 N = N + 1 V(R, C) = N Next C Next R Test = V End Function
当我按ctrl+shift+enter
键入=Test()
到3×4范围的单元格时,我得到预期的结果:
1 2 3 4 5 6 7 8 9 10 11 12
所以现在假设我想调整数组的大小。 我试着改变这个function:
Function Test() As Variant Dim V() As Variant Dim N As Long Dim R As Long Dim C As Long For R = 1 To 3 For C = 1 To 4 N = N + 1 ReDim Preserve V(1 To R, 1 To C) V(R, C) = N Next C Next R Test = V End Function
因为我使用vba IDE,所以我不认为我有任何诊断为什么上面只返回#VALUE
。 我究竟做错了什么?
在我的testing中,在直接窗口中调用此方法会抛出索引超出范围的错误。 然后我通过代码,问题是以下行:
ReDim Preserve V(1 To R, 1 To C)
对于For R
循环中的第一次运行(当R为1时),这是没有问题的,当内部For C
循环结束时,该数组的大小可以是(1 to 1, 1 to 4)
。
但是,只要For R
进入第二个循环(当R是2时),它将被调整为(1 to 2, 1 to 1)
,所以有效地尝试减小第二个维度的大小,这会引起错误Preserve
声明。 删除Preserve
语句可以消除错误,但也会在第二维中导致数据丢失。
为了解决这个问题,你必须在开始遍历数组并填充数组之前设置数组维的最终大小(所以你永远不会减小大小)。 但是维度的大小可以是dynamic的,例如像这样的方法参数提供:
Function Test(MaxR As Long, MaxC As Long) As Variant Dim V() As Variant Dim N As Long Dim R As Long Dim C As Long 'Set array size ReDim Preserve V(1 To MaxR, 1 To MaxC) 'Then start filling array For R = 1 To MaxR For C = 1 To MaxC N = N + 1 V(R, C) = N Next C Next R Test = V End Function
然后你可以在数组公式中使用该方法( ctrl+shift+enter
)来获得3×4范围的单元格。
=Test(3; 4)
从ReDim声明的MSDN页面:
- resize与保留。 如果使用Preserve,则只能调整数组的最后一个维度。 对于其他维度,您必须指定现有数组的边界。
例如,如果数组只有一个维度,则可以调整该维度的大小,并保留该数组的所有内容,因为您正在更改最后一个维度。 但是,如果数组具有两个或更多维度,则只有使用“保留”才能更改最后维度的大小。
所以问题是试图重新排列第一级 ( R或第一维)。 你不能用Preserve做到这一点。 但是,您可以使用“保留所有您想要的” 来重新排列第二个等级( C或第二维)。
ReDim Preserve V(1 To 3, 1 To 1) For R = 1 To 3 For C = 1 To 4 N = N + 1 ReDim Preserve V(LBound(V, 1) To UBound(V, 1), 1 To C) V(R, C) = N Next C Next R
如果要重定义二维数组的第一个等级是关键任务,那么首先要对其进行转置。
ReDim Preserve V(1 To 1, 1 To 1) For R = 1 To 3 V = application.Transpose(V) ReDim Preserve V(LBound(V, 1) To UBound(V, 1), LBound(V, 2) To R) V = application.Transpose(V) For C = 1 To 4 N = N + 1 ReDim Preserve V(LBound(V, 1) To UBound(V, 1), LBound(V, 2) To C) V(R, C) = N Next C Next R
我已经看到这在循环中使用更多的“行”到一个二维数组,但转置有限制,这是额外的处理,尽pipe在内存中。