Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

Im looking for someone who can improve my code, because at the moment it takes 4 minutes to execute. I'm new to VBA so it's probably bad coding. Normally if you are good in VBA you will understand the code, if not please ask more information.

Here is the code:

Sub InternExtern()

Dim source, addrescell, destination As Range
Dim Sourcevalue As String


For Each source In Range("E6", Range("E" & Rows.Count).End(xlUp))
 If source.Value <> "" Then
    For Each addrescell In Range("address_table_names").Rows
             If addrescell.Cells(1).Value <> "" And InStr(source.Offset(0, 23).Value, "Extern") = 0 Then
               SourceName = addrescell.Cells(1).Value
               Sourcevalue = addrescell.Cells(1, 4).Value
                    If InStr(UCase(source), UCase(SourceName)) <> 0 Then
                      If InStr(Sourcevalue, "10.") <> 0 Or InStr(Sourcevalue, "192.168.") <> 0 Or IsInternal(addrescell.Offset(0, 3).Value) Then
                       source.Offset(0, 23) = "Intern"
                       Else: source.Offset(0, 23) = "Extern"
                      End If
                    End If
                      If InStr(source, "-ext-") <> 0 Or InStr(source, "any") <> 0 Or InStr(source, "-EXT-") <> 0 Then
                      source.Offset(0, 23) = "Extern"
                      End If
                      If InStr(source, "any") <> 0 And InStr(source.Offset(0, -1).Value, "FW-Peering") = 0 Then
                      source.Offset(0, 23) = "Intern"
                      End If

            End If
            Next addrescell
End If
Next source

Some information you need to know:

The IsInternal function, is very basic and short, its not the reason why the code takes so long to execute.

the range in E6 counts more than 1000 rows. the "address_table_names" name range is in another sheet and contains +- 800 rows.

If there are other things you don't understand, please ask.

share|improve this question
1  
using cells is much slower than using arrays: see this for using arrays in excel –  Sean Cheshire Mar 14 '13 at 16:25
    
thanks for the info. –  user2156096 Mar 15 '13 at 9:08
add comment

migrated from stackoverflow.com Mar 14 '13 at 18:39

This question came from our site for professional and enthusiast programmers.

4 Answers

This code took 1.3 seconds with 1000 rows in each table.

Sub InternExtern2()

    Dim vaSource As Variant
    Dim vaAddress As Variant
    Dim i As Long, j As Long
    Dim rRng As Range
    Dim snStart As Single

    snStart = Timer

    With Sheet1
        Set rRng = .Range("E6", .Cells(.Rows.Count, 5).End(xlUp)).Offset(, -1).Resize(, 24)
    End With
    vaSource = rRng.Value
    vaAddress = Sheet2.Range("address_table_names").Value

    For i = LBound(vaSource, 1) To UBound(vaSource, 1)
        If Len(vaSource(i, 2)) > 0 And InStr(1, vaSource(i, 24), "Extern") = 0 Then
            For j = LBound(vaAddress, 1) To UBound(vaAddress, 1)
                If Len(vaAddress(j, 1)) > 0 Then
                    If InStr(1, vaSource(i, 2), vaAddress(j, 1)) > 0 Then
                        If IsExternal(vaSource(i, 2), vaSource(i, 1), vaAddress(j, 4), vaAddress(j, 3)) Then
                            vaSource(i, 23) = "Extern"
                        Else
                            vaSource(i, 23) = "Intern"
                        End If
                    End If
                End If
            Next j
        End If
    Next i

    rRng.Value = vaSource

    Debug.Print Timer - snStart

End Sub

Public Function IsInternal(vValue As Variant) As Boolean

    IsInternal = True

End Function

Public Function IsExternal(ByVal sSource As String, ByVal sSource2 As String, ByVal sAddress As String, ByVal sAddress2 As String) As Boolean

    Dim bReturn As Boolean

    bReturn = InStr(1, sAddress, "10.") = 0
    bReturn = bReturn Or InStr(1, sAddress, "192.168.") = 0
    bReturn = bReturn Or Not IsInternal(sAddress2)
    bReturn = bReturn Or InStr(1, UCase(sSource), "-EXT-") > 0
    bReturn = bReturn Or InStr(sSource, "any") > 0
    bReturn = bReturn Or InStr(1, sSource2, "FW-Peering") > 0

    IsExternal = bReturn

End Function

The Boolean logic isn't the same (so don't rely on that), but the looping is. As has been mentioned, working with arrays instead of Ranges is much faster. It's actually the writing to the cells that's really slow (reading too, but not as much). In this code, I'm reading the whole range into a 1000x24 array, changing a piece of the array, and writing it back in one fell swoop.

Note that the method used here has some drawbacks. If you have formulas in column D:Z, using this method will overwrite them with values. If that is the case, then use multiple arrays to pull in only the columns you need as opposed to one big array. It seems you're only using D, E, and Z, so you could create three array variables, read in only those columns, and write out only Z. The performance won't change with three arrays or one.

You were checking column Z for "Extern" inside of the address loop. If you check it outside of that loop and it's false, then the loop never runs and that saves cycles. Be very careful about checking anything in 'source' inside of the 'address' loop. If you can move it out of that loop, do it.

Very minor, but checking that the Len of a string is 0 is faster than checking if the string is "" (empty string). It has to do with how computers store strings (they're arrays and checking the upper bound of the array is faster than reading in the whole string array even if it's empty).

Without knowing all of the details, it seems like this would be even faster using worksheet functions and no VBA. But you may have your reasons.

share|improve this answer
add comment

If possible, deactivate autocalculation, visibbillity etc.

Application.ScreenUpdating = False
Application.Calculation = xlManual

And set it back to normal values at the end. If this does not help, we can look at your code.

share|improve this answer
1  
indeed these are usually the first things to do. To avoid strange settings you can store the current values in a (local) Variable before you apply the lines as given by Christian Sauer. Then setting them back at the end would be applying those stored values to the Application.ScreenUpdating and Application.Calculation –  K_B Mar 14 '13 at 16:14
    
thanks for the info. –  user2156096 Mar 15 '13 at 9:09
add comment

As mentioned by Christian you should turn

Application.ScreenUpdating = False
Application.Calculation = xlManual

Dimming multiple variables in 1 line doesnt work as expected:

Dim source, addrescell, destination As Range

Will Dim only destination as a Range and the other two as Variant, to get the proper dimensioning you should do:

Dim source As Range
Dim addrescell As Range
Dim destination As Range

I don't know if this would speed it up, but it is more properly.


Always use Value2 to get and let Cell/Range values, unless you want the explicit formatting applied to the value you get from the sheet. Value2 is the actual value of the cell without any formatting applied. Referring to that might speed things up a bit.

I notice that setting values back is done without use of either Value or Value2, I personally would use Value2 there as well.

share|improve this answer
    
screenupdating was already set to false, but i added the calculation line, changed all my ".value" to ".value2" and indeed from 4min. to 3min. Thanks! Allthought i should work with arrays. As i said before, im new to programming and VBA so it will take me a while to understand the array stuff. Meanwhile, feel free to upgrade my code in arrays. Thanks in advance! –  user2156096 Mar 15 '13 at 9:08
    
+1 I use VBA all the time and never knew about value2! –  Gaffi Mar 21 '13 at 14:09
add comment

As previously mentioned by @K_B, Value2 is significantly faster than Value and use it whenever possible.

The largest time savings would be to utilize arrays as opposed to cells, as mentioned by Sean Cheshire in the comments. My thesis model took ages to run (approx. 10 mins) utilizing cells but I was able to drop it to near 1 minute with arrays.

I would have voted up the comment by Mr. Cheshire however I don't have sufficient reputation - props Mr. Cheshire.

share|improve this answer
    
thanks for the info. –  user2156096 Mar 15 '13 at 9:09
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.