Solved

Alternative to Case

Posted on 2006-06-22
12
268 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
Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

 
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
 
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

Courses: Start Training Online With Pros, Today

Brush up on the basics or master the advanced techniques required to earn essential industry certifications, with Courses. Enroll in a course and start learning today. Training topics range from Android App Dev to the Xen Virtualization Platform.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Article by: Kraeven
Introduction Remote Share is a simple remote sharing tool, enabling you to see, add and remove remote or local shares. The application is written in VB.NET targeting the .NET framework 2.0. The source code and the compiled programs have been in…
It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
This is used to tweak the memory usage for your computer, it is used for servers more so than workstations but just be careful editing registry settings as it may cause irreversible results. I hold no responsibility for anything you do to the regist…
Although Jacob Bernoulli (1654-1705) has been credited as the creator of "Binomial Distribution Table", Gottfried Leibniz (1646-1716) did his dissertation on the subject in 1666; Leibniz you may recall is the co-inventor of "Calculus" and beat Isaac…

813 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

13 Experts available now in Live!

Get 1:1 Help Now