仅适用于具有一个元素的数组的循环

时间:2016-08-10 07:11:37

标签: vba excel-vba excel

我有一个几乎可以运行的宏:

宏根据单元格组合的内容填充字符串。

输入是我转换为数组的范围。列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语句来处理这种情况,但是却想不出一种方法可以让这个方法适用于具有单个值的数组。

我可以使用哪些其他功能来获得相同的结果,但能够处理数组中的单个值?

5 个答案:

答案 0 :(得分:2)

问题的根源是第Set GclR = .Range("E3", .Range("E3").End(xlDown))行。当E3中只有一个值且下面没有其他值时,您的代码将向下返回工作表底部的范围。正如你所说,你将搜索1,000,000多个空单元格。

要解决此问题,您有两种选择:

  1. 如果预期数据下方的列E中没有其他数据,请从下往上查找范围。

    Set GclR = .Range("E3", .Cells(.Rows.Count, 5).End(xlUp))
    
  2. 如果您必须首先使用.End(xlDown)测试空白单元格

    If IsBlank(.Range("E4")) Then
        Set GclR = .Range("E3")
    Else
        Set GclR = .Range("E3", .Range("E3").End(xlDown))
    EndIf
    
  3. 在这两种情况下,您都可以将单个单元格范围返回到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