我有一个几乎可以运行的宏:
宏根据单元格组合的内容填充字符串。
输入是我转换为数组的范围。列E3在从第3行及以下开始的单元格中具有值。
With ActiveWorkbook.Worksheets("Sheet2")
Set GclR = .Range("E3", .Range("E3").End(xlDown))
End With
GclArr = GclR.Value
阵列的大小从不存在到半打长度不等。 我的代码遍历内容并找到每个值并将其放入字符串中的相应位置。
它跳闸的地方是当数组中的值少于2时。 Excel挂起并崩溃。
我认为这是由于For循环:
If GclArr(1, 1) <> 0 Then
If Gcl <> 0 Then
For R = 1 To UBound(GclArr, 1)
GclStr = GclStr & GclArr(R, 1) & " " & Gcl & " "
Next R
End If
End If
如果R = 1且UBound(GclArr,1)也= 1,则For循环似乎变得困惑。 (如果UBound为2或更大,它的效果非常好。)
当数组为空时,我使用了一个If语句来处理这种情况,但是却想不出一种方法可以让这个方法适用于具有单个值的数组。
我可以使用哪些其他功能来获得相同的结果,但能够处理数组中的单个值?
答案 0 :(得分:2)
问题的根源是第Set GclR = .Range("E3", .Range("E3").End(xlDown))
行。当E3
中只有一个值且下面没有其他值时,您的代码将向下返回工作表底部的范围。正如你所说,你将搜索1,000,000多个空单元格。
要解决此问题,您有两种选择:
如果预期数据下方的列E
中没有其他数据,请从下往上查找范围。
Set GclR = .Range("E3", .Cells(.Rows.Count, 5).End(xlUp))
如果您必须首先使用.End(xlDown)
测试空白单元格
If IsBlank(.Range("E4")) Then
Set GclR = .Range("E3")
Else
Set GclR = .Range("E3", .Range("E3").End(xlDown))
EndIf
在这两种情况下,您都可以将单个单元格范围返回到GclR
。当发生这种情况时,CclR.Value
将不成为一个数组。要处理这个用途
If GclR.Cells.Count = 1 Then
ReDim GclArr(1 to 1, 1 to 1)
GclArr(1, 1) = GclR.Value
Else
GclArr = GclR.Value
EndIf
然后,您可以使用原始的For循环代码
答案 1 :(得分:1)
如果只有迭代(参见示例)
,for循环没有问题Sub ForLoopTest()
Dim iItem As Long
For iItem = 1 To 1
MsgBox (iItem)
Next iItem
End Sub
您是否认为VBA数组索引默认为0开始。因此,在这种情况下,UBound(GclArr,1)的值为0.为了消除这类问题,LBound(GclArr,1)To UBound(GclArr, 1)可以使用语法。
If GclArr(1, 1) <> 0 Then
If Gcl <> 0 Then
For R = LBound(GclArr, 1) To UBound(GclArr, 1)
GclStr = GclStr & GclArr(R, 1) & " " & Gcl & " "
Next R
End If
End If
模块开头的Option Base 1语句可以修改此行为。在这种情况下,数组的第一个元素的索引将为1.
答案 2 :(得分:1)
Private Sub sb_ForTest()
Dim i&
For i = 1 To 1
Debug.Print i ' I have everything working
Next
End Sub
Re:cyboashu
完美适用于数组中的一行。但正如OP所说,他得到了 他的数组的动态范围。所以这个答案会在那里失败。也, 添加一些关于代码的上下文是个好主意。只有代码 你的答案比一些代码+的回答有点帮助 说明。 :)
OP写了 “如果R = 1而UBound(GclArr,1)也= 1,似乎For循环变得混乱。(如果UBound是2或更大,它完全可行。) 强>
这句话不对,我赶紧纠正他:) 很抱歉没有在我的消息的前面引用他...
此外,他在问题标题中提出了问题 “For Loop for Array with Only One Element” :)
我只写了For ... Loop功能,不管其他代码传递给它的真实边界。
答案 3 :(得分:1)
所以当我在该范围内只有一个值时,我检查了UBound的值是多少。它的单元格限制为1048574.这可能是我的范围定义函数的结果:
Set GclR = .Range("E3", .Range("E3").End(xlDown))
和
GclArr = GclR.Value
鉴于上述情况,我认为Excel实际上并没有崩溃,但是花了很长时间才无意义地处理这么大的数组。
基于此,我使用额外的If语句进行了以下解决方法:
If Gcl <> 0 Then
If GclArr(1, 1) <> 0 Then
If GclArr(2, 1) = 0 Then
GclStr = GclStr & GclArr(1, 1) & " " & Gcl & " "
Else
For R = 1 To UBound(GclArr, 1)
GclStr = GclStr & GclArr(R, 1) & " " & Gcl & " "
Next R
End If
End If
End If
If语句检查非常大的数组中第二行的值是什么,如果它是零(意味着第一行之后没有数据),则避免使用For循环,而是使用特定函数处理数组第一行的值。
拥有如此多的If语句并不是很优雅,但它完美无缺。
如果它存在,我仍然希望使用更优雅的东西。
答案 4 :(得分:0)
你可以避免循环并进行直接连接(在缩小你的范围并查找之后),即
Sub Recut()
Dim Gcl As Long
Dim GclStr As String
Dim rng1 As Range
Gcl = 3
With Sheets("Sheet2")
Set rng1 = .Range(.[e3], .Cells(Rows.Count, "E").End(xlUp))
End With
If rng1.Cells.Count > 1 Then GclStr = Join(Application.Transpose(rng1), " " & Gcl & " ")
End Sub