我有一个for循环,在其中有if语句。
在我的Excel中,我有一个包含一次每个值的列表。一旦找到它,我什至不希望代码甚至检查条件,我希望它在每次执行循环时完全跳过if语句的这一部分,有可能吗?
循环的第一次迭代将发现“ c”是值,因此它将执行其内部的操作(xc = i)
我不希望代码再次检查“ ElseIf Cells(1,i)=“ c”,如下图所示,这可能吗?
代码为文本:
Sub test()
Dim i, xa, xb, xc As Integer
For i = 1 To 5
If Cells(i, 1) = "a" Then
xa = i
ElseIf Cells(i, 1) = "b" Then
xb = i
ElseIf Cells(i, 1) = "c" Then
xc = i
End If
Next i
End Sub
答案 0 :(得分:2)
我对您的需求的最初解释是“如果代码再次击中'c',那就不要采取行动”。
为此,您可以按以下方式修改逻辑:
ElseIf (xc = 0) And (Cells(i, 1) = "c") Then
这样,一旦设置xc
,第一个布尔表达式将为False,并且将永远不会再满足整体条件。如@TimWilliams所述,VBA仍将评估第二个布尔表达式,这与其他具有短路选项的语言不同。 @Gene的答案描述了解决此问题的方法。通常,为了获得更好的性能,您应该先评估简单的条件,然后再诉诸昂贵的条件。
附加说明
在VBA中,必须为每个变量指定一个类型。在您的Dim
行中,只有xc是一个整数,而其他变量是Variants。
一个不合格的Cells()
调用在当前活动的工作表上进行,这可能不是预期的。建议:使用工作表的代号限定Cells()
。您可以在工作表的(Name)
属性下看到或指定的CodeName(从Visual Basic编辑器中可以看到)。例如,如果(Name)
是Sheet1
,请使用Sheet1.Cells()
。仅当代码与Sheet1
位于同一工作簿中时,此方法才有效。如果代码位于工作表本身的后面,您甚至可以使用Me.Cells()
。
当像处理代码一样处理单元格值时,VBA(安静地)很友好,并且了解到Range
类的众多属性中,Value
是您感兴趣的。但是,最好在Sheet1.Cells(i, j).Value
中明确声明目标属性。
编辑
知道这些值将是不同的并且它们中大约有60个,我建议您简单地使用一个Dictionary(如下所示)来一次性获得每个值的行,而不必级联If
:
Option Explicit
Sub test()
Dim i As Integer
Dim dict As Object 'Scripting.Dictionary
Set dict = CreateObject("Scripting.Dictionary")
For i = 1 To 5
dict(Cells(i, 1).Value) = i
Next
Debug.Print dict("a") '4
Debug.Print dict("b") '2
Debug.Print dict("c") '1
'Etc.
End Sub
答案 1 :(得分:0)
如果我理解您的问题,可以尝试以下代码:
Sub test()
Dim i, xa, xb, xc As Integer
Dim a, b, c As Boolean
a = False
b = False
c = False
For i = 1 To 5
If Cells(i, 1) = "a" And a <> True Then
xa = i
a = True
ElseIf Cells(i, 1) = "b" And b <> True Then
xb = i
b = True
ElseIf Cells(i, 1) = "c" And c <> True Then
xc = 1
c = True
End If
Next i
End Sub
仅当跳过单元格(i,1)=“ a”并跳过下一个“ a”值之后,才将布尔变量设置为true。
希望这会有所帮助
答案 2 :(得分:0)
我想我只是想“修改” Ferdinando的代码,所以它更具“可读性”。此版本与费迪南多(Ferdinando)或Excelosaurus(Excelosaurus)之间的主要(实质性)区别在于,一旦检测到该值,该单元甚至不会进行测试。请记住,问题是:我不希望代码再次检查“ ElseIf Cells(1,i)=” c“ ... 所以,此版本正是这样做的。
Sub test()
Dim i As Integer, xa As Integer, xb As Integer, xc As Integer
Dim aFound As Boolean, bFound As Boolean, cFound As Boolean
Dim r As Range
For i = 1 To 5
Set r = Cells(i, 1)
If Not aFound Then
If r = "a" Then xa = i: aFound = True
ElseIf Not bFound Then
If r = "b" Then xb = i: bFound = True
ElseIf Not cFound Then
If r = "c" Then xc = i: cFound = True
End If
Next i
End Sub
答案 3 :(得分:0)
我不喜欢60个ElseIfs的想法。请检查下面的代码。为了对其进行测试,创建一个名为“ TestSheet”的工作表,并将A1:A5输入到单元格H2:H6。
Sub TestSpike()
' 06 Jan 2019
Dim Rng As Range
Dim Items As Variant
Dim Spike As String
Dim Tmp As String
Dim i As Integer
Dim R As Long
Items = Split("c|b|0|a|1", "|")
With Worksheets("TestSheet").Columns("H")
For R = 2 To 6
Tmp = CStr(.Cells(R).Value)
If InStr(1, Spike, Tmp, vbTextCompare) = 0 Then
Spike = Spike & "|" & Tmp
On Error Resume Next
i = Application.WorksheetFunction.Match(Tmp, Items, 0)
If Err Then
MsgBox Tmp & " wasn't found in Array"
Else
MsgBox "i = " & i & " = Item " & Tmp
End If
End If
Next R
End With
End Sub
该代码带有“尖峰”。首先根据Spike检查每个项目。如果找到,则不进行进一步测试。否则,它已添加到Spike中。 在将新项目添加到Spike之后,将对可容纳60个元素的数组“ Items”进行检查,这些数组由Chr(124)分隔,因此,Split(“ c | b | 0 | a | 1”,“ |” )。我使用工作表函数MATCH在数组中查找项目。结果是索引号(如果找不到,则为错误)。您可以在Select Case语句中使用此索引号来处理彼此不同的每个项目,基本上与现在If语句返回True时处理它的方式相同。 您可能会发现对这种设置有用的一个想法是使用Match函数的索引从另一个数组返回一个值。例如,另一个数组可能包含函数名称,并且您使用Application.Run为每个项目调用不同的函数。这比检查60多个Select Case语句要快得多。