重构嵌套'如果'声明

时间:2015-09-29 04:53:17

标签: excel vba excel-vba

这是一些代码,它循环遍历电子表格中的某个区域,并根据源单元格不包含值"(空白)"的条件执行代码。代码有效,但以这种方式运行嵌套的if语句效率很低。从长远来看,我一直试图提高效率,但我没有想法。

有什么建议吗?

Sub NestedIfStatement()
Dim lastrow1 As Long
Dim I As Integer, J As Integer, N As Integer, MaxPriority as Integer
Dim Maxnumber as Range
Dim WS1 As Worksheet, WS3 as Worksheet
Dim WB As Workbook

Set WB = ThisWorkbook
Set WS1 = WB.Worksheets("Config")
Set WS2 = WB.Worksheets("Data")
Set WS3 = WB.Worksheets("Status Report") 

lastrow1 = WS1.Cells(Rows.Count, 1).End(xlUp).Row
I = 1
J = 1    
N = 3
Set Maxnumber = WS1.Range("A" & I & ":A" & lastrow1)
    MaxPriority = Application.Max(Maxnumber)

For J = 1 To lastrow1
    If WS1.Cells(J, 1) <= MaxPriority Then
       If WS1.Cells(J, 6).Value <> "(blank)" Then
          WS3.Cells(N, 7).Value = WS1.Cells(J, 6).Value
       End If
       If WS1.Cells(J, 5).Value <> "(blank)" Then
          WS3.Cells(N, 6).Value = WS1.Cells(J, 5).Value
       End If
       If WS1.Cells(J, 4).Value <> "(blank)" Then
          WS3.Cells(N, 4).Value = WS1.Cells(J, 4).Value
       End If
       If WS1.Cells(J, 3).Value <> "(blank)" Then
          WS3.Cells(N, 3).Value = WS1.Cells(J, 3).Value
       End If
       If WS1.Cells(J, 2).Value <> "(blank)" Then
          WS3.Cells(N, 2).Value = WS1.Cells(J, 2).Value
       End If
       N = N + 1
    End If
Next J

End Sub

2 个答案:

答案 0 :(得分:2)

您是否尝试在循环之前将计算模式切换为手动,然后在循环后将其切换回来?您所描述的内容就像在WS3中的每次更改都要刷新很多计算。关闭ScreenUpdating可能会有所帮助。

所以,像这样:

Dim CalcMode As Long
'...
Application.ScreenUpdating = False
CalcMode = Application.Calculation
Application.Calculation = xlCalculationManual ' Change it to manual update
For J = 1 To lastrow1
    '...
Next
Application.Calculation = CalcMode ' Restore to what it was before
Application.ScreenUpdating = True

或者,您可以将WS1中的值加载到Array(Variant)中,然后执行嵌套的If。

您可能遇到的另一个问题是,在循环填充详细信息之前,您没有清除WS3的内容,从而产生无关数据。

<小时/> 编辑(可能的解决方案)

根据您的代码尝试实现的内容,您可以使用VBA将Formula分配给关联的单元格 - 无循环!

假设WS3中的第2行有一个标题,则列B,C,D的结果 FormulaR1C1 为:
=IF(Config!R[-2]C<>"(blank)",Config!R[-2]C,"")
和列F, G是:=IF(Config!R[-2]C[-1]<>"(blank)",Config!R[-2]C[-1],"")

为了使公式更通用,我将'<S1>'放入const字符串中。 lastrow3基本上是WS3中需要这些公式的最后一行,它取决于WS1的A列中使用的行数。

请按时间差异并使用此代码回发,我们都对现实世界数据的效率感到好奇。

Option Explicit

Sub NestedIfStatement()
    Const Formula_FG = "=IF('<S1>'!R[-2]C[-1]<>""(blank)"",'<S1>'!R[-2]C[-1],"""")"
    Const Formula_BCD = "=IF('<S1>'!R[-2]C<>""(blank)"",'<S1>'!R[-2]C,"""")"

    Dim CalcMode As Long, sFormula As String
    Dim lastrow3 As Long
    Dim WS1 As Worksheet

    Application.ScreenUpdating = False
    CalcMode = Application.Calculation
    Application.Calculation = xlCalculationManual

    With ThisWorkbook
        Set WS1 = .Worksheets("Config")
        lastrow3 = WS1.Cells(Rows.Count, 1).End(xlUp).Row + 2 ' Offset from row 1 to 3 (N)
        With .Worksheets("Status Report")
            .UsedRange.Offset(1, 0).ClearContents ' Remove old data below the header row
            sFormula = Replace(Formula_BCD, "<S1>", WS1.Name)
            .Range("B3:D" & lastrow3).FormulaR1C1 = sFormula
            sFormula = Replace(Formula_FG, "<S1>", WS1.Name)
            .Range("F3:G" & lastrow3).FormulaR1C1 = sFormula
        End With
        Set WS1 = Nothing
    End With

    Application.Calculation = CalcMode
    Application.ScreenUpdating = True

End Sub

答案 1 :(得分:1)

您的变量声明和赋值中有许多漏洞无法正确转录为变量数组方法,但这可能会有所帮助。

Sub Nested_UnIf_Statement()
    Dim WS1 As Worksheet, WS3 As Worksheet, Maxnumber As Range
    Dim lastrow1 As Long, I As Long, N As Long, MaxPriority As Long
    Dim v As Long, vWS1s As Variant, vWS3BDs As Variant, vWS3FGs As Variant

    Debug.Print Timer
    Set WS1 = Worksheets("Sheet2")
    Set WS3 = Worksheets("Sheet3")

    I = 2
    With WS1
        lastrow1 = .Cells(Rows.Count, 1).End(xlUp).Row
        Set Maxnumber = .Range("A" & I & ":A" & lastrow1)
        MaxPriority = Application.Max(Maxnumber)
        vWS1s = WS1.Range("A" & I & ":F" & lastrow1).Value2
        ReDim vWS3BDs(1 To 3, 1 To 1)
        ReDim vWS3FGs(1 To 2, 1 To 1)
    End With

    For v = LBound(vWS1s, 1) To UBound(vWS1s, 1)
        If vWS1s(v, 1) <= MaxPriority Then
            vWS3BDs(1, UBound(vWS3BDs, 2)) = Replace(vWS1s(v, 2), "(blank)", "")
            vWS3BDs(2, UBound(vWS3BDs, 2)) = Replace(vWS1s(v, 3), "(blank)", "")
            vWS3BDs(3, UBound(vWS3BDs, 2)) = Replace(vWS1s(v, 4), "(blank)", "")
            vWS3FGs(1, UBound(vWS3FGs, 2)) = Replace(vWS1s(v, 5), "(blank)", "")
            vWS3FGs(2, UBound(vWS3FGs, 2)) = Replace(vWS1s(v, 6), "(blank)", "")
            ReDim Preserve vWS3BDs(LBound(vWS3BDs, 1) To UBound(vWS3BDs, 1), LBound(vWS3BDs, 2) To UBound(vWS3BDs, 2) + 1)
            ReDim Preserve vWS3FGs(LBound(vWS3FGs, 1) To UBound(vWS3FGs, 1), LBound(vWS3FGs, 2) To UBound(vWS3FGs, 2) + 1)
        End If
    Next v

    ReDim Preserve vWS3BDs(LBound(vWS3BDs, 1) To UBound(vWS3BDs, 1), LBound(vWS3BDs, 2) To UBound(vWS3BDs, 2) - 1)
    ReDim Preserve vWS3FGs(LBound(vWS3FGs, 1) To UBound(vWS3FGs, 1), LBound(vWS3FGs, 2) To UBound(vWS3FGs, 2) - 1)

    N = 3
    WS3.Cells(N, 2).Resize(UBound(vWS3BDs, 2), UBound(vWS3BDs, 1)) = _
       Application.Transpose(vWS3BDs)
    WS3.Cells(N, 2).Offset(0, UBound(vWS3BDs, 1) + 1).Resize(UBound(vWS3FGs, 2), UBound(vWS3FGs, 1)) = _
       Application.Transpose(vWS3FGs)

    Debug.Print Timer

End Sub

在5000行随机数据上,您的原始例程在00:00:01.10秒运行,而这一行在00:00:00.13秒运行。结果完全相同。