Solved

Alternative to Case

Posted on 2006-06-22
12
265 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
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Get String split 5 48
update textboxes with Streamreader 21 42
send messages to whatsapp programatically 2 13
Variable Event ? 3 23
This tutorial demonstrates one way to create an application that runs without any Forms but still has a GUI presence via an Icon in the System Tray. The magic lies in Inheriting from the ApplicationContext Class and passing that to Application.Ru…
Parsing a CSV file is a task that we are confronted with regularly, and although there are a vast number of means to do this, as a newbie, the field can be confusing and the tools can seem complex. A simple solution to parsing a customized CSV fi…
Windows 10 is mostly good. However the one thing that annoys me is how many clicks you have to do to dial a VPN connection. You have to go to settings from the start menu, (2 clicks), Network and Internet (1 click), Click VPN (another click) then fi…
In this video I am going to show you how to back up and restore Office 365 mailboxes using CodeTwo Backup for Office 365. Learn more about the tool used in this video here: http://www.codetwo.com/backup-for-office-365/ (http://www.codetwo.com/ba…

863 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