Solved

Alternative to Case

Posted on 2006-06-22
12
264 Views
Last Modified: 2008-03-17
I am using a case statement to take an input string and return a call to a function.

Example:
Select Case sSwitch
   Case "ABC"
      Return FunctionABC
   Case "XYZ"
      Return FunctionXYZ
...
End Select

The problem that i have is that there are several hundred cases, and it is in a loop, so it is taking a real long time..  Is there a VB.Net statement or construct that can search through a list of cases and return a function pointer? Or some other method that would be faster?

Thanks!
0
Comment
Question by:a1x
  • 6
  • 2
  • 2
  • +2
12 Comments
 
LVL 18

Expert Comment

by:JR2003
ID: 16964805
You could nest case statement and test the first character.

Select Case Left(sSwitch, 1)
   Case "A"
        Select Case sSwitch
           Case "ABC"
              Return FunctionABC
           Case "ABD"
              Return FunctionABD
        End Select
   Case "B"
        Select Case sSwitch
           Case "BCD"
              Return FunctionBCD
           Case "BDS"
              Return FunctionBDS
        End Select
   Case "C"
        Select Case sSwitch
           Case "CDE"
              Return FunctionCDE
           Case "CDF"
              Return FunctionCDF
        End Select
...
End Select

That way you reduce the average number test for each item.
0
 
LVL 62

Accepted Solution

by:
Fernando Soto earned 415 total points
ID: 16965370
Hi a1x;

Here is a way to do it without a Case statements.

    ' Declear pointer to a function using Delegate
    Delegate Function delFunction() As String

    ' Hash table to hold key / value pair
    Dim ht As New Hashtable

    Private Sub Form1_Load(ByVal sender As Object, _
        ByVal e As System.EventArgs) Handles MyBase.Load

        ' Load Hash table with the key and pointer to function to call
        Dim func As delFunction
        func = AddressOf FunctionABC
        ht.Add("ABC", func)
        func = AddressOf FunctionDEF
        ht.Add("DEF", func)

    End Sub

Then you can call them this way which is much faster then going through 100 case test.

    Private Sub Button1_Click(ByVal sender As Object, _
        ByVal e As System.EventArgs) Handles Button1.Click

        Dim deleg As delFunction
        deleg = CType(ht("ABC"), delFunction)
        Console.WriteLine(deleg())
        deleg = CType(ht("DEF"), delFunction)
        Console.WriteLine(deleg())

    End Sub

    Private Function FunctionABC() As String
        Return "ABC"
    End Function

    Private Function FunctionDEF() As String
        Return "DEF"
    End Function

Fernando
0
 
LVL 34

Expert Comment

by:Sancler
ID: 16967598
I doubt very much that it is your use of SELECT CASE that is causing your program to take "a real long time".  Try this

    Private Sub MakeCode(ByVal FileName As String)
        Dim sr As New StreamWriter(FileName)
        sr.WriteLine("Dim ticks As Long = Now.Ticks")
        sr.WriteLine("for a as integer = 1 to 1000")
        sr.WriteLine("dim b as string = cstr(a)")
        sr.WriteLine("select case a")
        For i As Integer = 1 To 1000
            Dim s As String = "Case " & Chr(34) & i.ToString & Chr(34)
            sr.WriteLine(s)
            s = "debug.writeline(" & Chr(34) & i.ToString & Chr(34) & ")"
            sr.WriteLine(s)
        Next
        sr.WriteLine("end select")
        sr.WriteLine("next")
        sr.WriteLine("Dim timelapse As Long = (Now.Ticks - ticks) / TimeSpan.TicksPerSecond")
        sr.WriteLine("MsgBox(timelapse)")
        sr.Close()
    End Sub

All it does is produce the code for a 1000 select case statement and code to loop through it looking for each value.  Although the values are derived from numbers they are expressed as strings to make it similar to your situation.

If you run that and then select all, copy and paste the text from the file it produces into a sub and run that sub I doubt that you will find it "taking a real long time".  Different systems will produce different results but, on mine, the result in the message box at the end was 2 seconds.

So my guess is that, if you want to reduce the time, you should be looking at the functions which your SELECT CASE routine is directing program flow to rather than at the SELECT CASE statement itself.

Roger
0
 
LVL 34

Expert Comment

by:Sancler
ID: 16968598
It just occurred to me that, although I had added the line

        sr.WriteLine("dim b as string = cstr(a)")

so as to produce a "text" select case rather than a "number" select case, to line up with yours, I did not change

        sr.WriteLine("select case a")

to

        sr.WriteLine("select case b")

I've now done that and re-run.  The time on my system is now down to 1 second ;-)

Roger
0
 
LVL 5

Author Comment

by:a1x
ID: 16971679
Thanks FernandoSoto!

Exactly what I was looking for.  Tremendous increase in speed.
0
 
LVL 62

Expert Comment

by:Fernando Soto
ID: 16972143
No problem glad I was able to help.
0
Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 16972236
You must have one LOOOOOOOOOOOOOOOOOOOOOOOOOOOOONG Form1_Load() sub eh?....   =)
0
 
LVL 34

Expert Comment

by:Sancler
ID: 16972288
"Tremendous increase in speed".  That's interesting.  I've just run comparative tests, using a similar approach to that outlined above.  That is, I wrote code to create 1000 instances of delegate functions and fill a hashtable with their addresses.  I then copied that code into a form and iterated through a 1000 loop to call each function once.  Here's the results.

Select case: 875 milliseconds
Select case: 594 milliseconds
Select case: 609 milliseconds
Select case: 578 milliseconds
Select case: 609 milliseconds
Select case: 797 milliseconds

Delegate: 1312 milliseconds
Delegate: 703 milliseconds
Delegate: 719 milliseconds
Delegate: 750 milliseconds
Delegate: 703 milliseconds
Delegate: 734 milliseconds

I must stress that I'm not arguing with Fernando's answer, or the award of points to him.  What matters is what works.

But I can't help wondering why.  It's just that, so far as I know, a SELECT CASE statement in fact works with, in the background, its own hashtable so I would have been surprised if, of itself, the upfront hashtable approach was any quicker.  My tests show that it isn't.  For all practical purposes it is the same.  So why, in the setting in this question, has it produced a "tremendous increase in speed"?

Any thoughts, anyone?

Roger
0
 
LVL 34

Expert Comment

by:Sancler
ID: 16972304
Mike

Yes it is.  My intermediate code file was 118KB ;-)

Roger

0
 
LVL 5

Author Comment

by:a1x
ID: 16972531
Perhaps you are on Framework 2.0?  I am on 1.1.

Do you have the code to create the hash table functions?.  I'm curious.
0
 
LVL 34

Expert Comment

by:Sancler
ID: 16972954
I did it in VB.NET 2003, Framework 1.1

Here's the code

    Private Sub MakeCode2(ByVal FileName As String)
        Dim sr As New StreamWriter(FileName)
        ' Declear pointer to a function using Delegate
        sr.WriteLine("Delegate Function delFunction() As String")

        ' Hash table to hold key / value pair
        sr.WriteLine("Dim ht As New Hashtable")

        sr.WriteLine("Private Sub Form1_Load(ByVal sender As Object,ByVal e As System.EventArgs) Handles MyBase.Load")

        ' Load Hash table with the key and pointer to function to call
        sr.WriteLine("Dim func As delFunction")
        For i As Integer = 1 To 1000
            sr.WriteLine("func = AddressOf Function" & i.ToString)
            sr.WriteLine("ht.Add(" & Chr(34) & i.ToString & Chr(34) & ", func)")
        Next
        sr.WriteLine("End Sub")
        For i As Integer = 1 To 1000
            sr.WriteLine("Private Function Function" & i.tostring & "() As String")
            sr.WriteLine("Return " & Chr(34) & i.ToString & Chr(34))
            sr.WriteLine("End Function")
        Next
        sr.Close()
        MsgBox("done")

    End Sub

The routine that I wrapped the iteration in, having used the above to generate the code which I copied into the form, was

    Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        Dim ticks As Long = Now.Ticks
        Dim deleg As delFunction
        For a As Integer = 1 To 1000
            deleg = CType(ht(a.ToString), delFunction)
            Debug.WriteLine(deleg())
        Next
        Dim timelapse As Long = (Now.Ticks - ticks) / TimeSpan.TicksPerMillisecond
        MsgBox(timelapse)
        Debug.WriteLine("Delegate: " & timelapse & " milliseconds")
    End Sub

The "Select Case" test just used the code from my earlier post, with the final output changed to debug and put in milliseconds.

Have fun with it.

Roger
0
 
LVL 34

Expert Comment

by:Sancler
ID: 16973011
I've just converted the project to VB.NET 2005, Framework 2 and re-run the tests.  Here's the results for those.

Select case: 1484 milliseconds
Select case: 1266 milliseconds
Select case: 1359 milliseconds
Select case: 1297 milliseconds
Select case: 1266 milliseconds
Select case: 1297 milliseconds

Delegate: 1734 milliseconds
Delegate: 1266 milliseconds
Delegate: 1219 milliseconds
Delegate: 1188 milliseconds
Delegate: 1172 milliseconds
Delegate: 1172 milliseconds

In relative terms the two methods are still, for all practical purposes, the same - although the slight edge that Select Case had before Delegate has now.  But the most interesting thing is that the 2003 version is quite a bit faster than the 2005 version.  There's progress for you!

Roger
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

A while ago, I was working on a Windows Forms application and I needed a special label control with reflection (glass) effect to show some titles in a stylish way. I've always enjoyed working with graphics, but it's never too clever to re-invent …
If you need to start windows update installation remotely or as a scheduled task you will find this very helpful.
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now