Announcement

Collapse
No announcement yet.

Multi-choice logic

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Multi-choice logic

    I was wondering if the following is the simplest structure for the condition, or if there's a more concise way to code it.

    The idea is to reject any value in Unit that does NOT begin with YR, MO, or DY.

    Code:
       Select Case UCase$(Left$(Unit, 2))
       Case "YR","MO","DY"
       Case Else
          Exit Function
       End Select
       '
       'processing for the YR, MO, DY values
    I have not yet had occasion to use Choose or Switch, but they don't seen appropriate...

    At one point I probably would have coded this as either a multi-clause IF, or a series of IFs, or a series of INSTRs...

    Have I stumbled upon the most concise code?

  • #2
    John,
    the following are all untested but are all more concise .. but that may be a matter of opinion.

    Paul.
    Code:
    k$=UCase$(Left$(Unit, 2))
    IF k$="YR" OR k$="MO" OR k$="DY" THEN
    
    'processing for the YR, MO, DY values
    
    END IF
    Code:
    IF INSTR("YR#MO#DY",UCase$(Left$(Unit, 2))) THEN  'where # is not a valid character in 'unit'
    
    'processing for the YR, MO, DY values
    
    END IF
    Code:
    IF INSTR("YRMODYyrmody",LEFT$(Unit, 2)) MOD 2 THEN  
    
    'processing for the YR, MO, DY values
    
    END IF
    Code:
    ON INSTR("YRyrMOmoDYdy",Left$(Unit, 2)) GOTO good,bad,good,bad,good,bad,good,bad,good,bad,good,bad
    bad:
    EXIT FUNCTION
    good:
    'processing for the YR, MO, DY values
    or, if you want to use CHOOSE
    Code:
    IF CHOOSE(INSTR("YRyrMOmoDYdy",Left$(Unit, 2)), 1,0,1,0,1,0,1,0,1,0,1) = 0 THEN EXIT FUNCTION
    'processing for the YR, MO, DY values
    and if you want to use SWITCH
    Code:
    k$=UCASE$(LEFT$(Unit, 2))	
    IF SWITCH(k$="YR",1,k$="MO",1,K$="DY",1) =0 THEN  EXIT FUNCTION
    'processing for the YR, MO, DY values
    Last edited by Paul Dixon; 2 Mar 2009, 10:29 PM.

    Comment


    • #3
      Originally posted by John Montenigro View Post
      I was wondering if the following is the simplest structure for the condition, or if there's a more concise way to code it.
      There are several other ways I could come up with. Are they more concise? Are they easier to understand? I think that is opinion.

      I'd personally use the select in this case. It is the simplest to read and understand.

      I use RegExpr if the search is more complex.
      The others presented I find take me long to understand 6 months later.

      The only difference is I would process in the case. I avoid using Exit Function, if possible. I try to have a single exit point to avoid programming errors.

      Code:
          tmpUnit = UCase$(Left$(UNIT,2)) ' need tmp variable to avoid repeating UCase/Left 
          If  TmpUnit ="YR" Or tmpUnit = "MO" Or TMPUnit= "DY" Then
              ' Process 
          End If
      Code:
       
          If InStr("YR,MO,DY,", UCase$(Left$(Unit,2)) & ",") > 0  Then
              ' Process
          End If
      Code:
          ' No need for left$  ^ forces beginning of line
          ' No need for ucase$, regexpr is case insensitive as written
          Local iPos As Long
          RegExpr "(^YR)|(^MO)|(^DY)" In Unit To iPos
          If iPos > 0 Then
              Process
          End If

      Comment


      • #4
        Thanks!

        Your examples cover alternatives I had considered plus a few I hadn't thought of.

        Paul, your examples for Choose and Switch help a lot - I couldn't imagine how I could appy them in this situation, but you've clarified what was gnawing at me - that there is a way, and it's almost as concise as Select, but not quite.

        Brian, I take your point about process exits - I've been gradually developing that style, and I see it's a bad habit I should and will change. I particularly appreciate the REGEXPR example - I always have trouble creating the masks, and your example helps explain some aspects I've not understood.

        As always, I really appreciate the support for my edumukation!

        Comment


        • #5
          The following should be pretty efficient since there is no string manipulation (you would need to add cases for lowercase... I only tested for the UCASE possibilities).

          Code:
          LOCAL pwUnit AS WORD PTR
          
          pwUnit = STRPTR( Unit)  'Use VARPTR if Unit is ASCIIZ
          
          IF @pwUnit <> &H5259 AND @pwUnit <> &H4F4D AND @pwUnit <> &H5944 THEN
             'No Match
          ELSE
             'Match
          END IF
          Last edited by Bern Ertl; 3 Mar 2009, 10:32 AM.
          Bernard Ertl
          InterPlan Systems

          Comment


          • #6
            A while ago I sent in a new feature suggestion...

            MEMBER (search_expr, expr, expr [,expr..] )

            Returns true if search_expr is equal to any ' expr', e

            n this case..
            Code:
             IF  ISFALSE  (MEMBER(Left(Unit,2), "MO", "YR", "DA"))  THEN 
                  ...
            Kind of a combination of SELECT CASE and ARRAY SEARCH, except it fits on one line and returns true or false in the function position.

            I would actually like expr to be an array so you could..
            Code:
              IF MEMBER (var , myarray()) ....  THEN 
               ......
            .. instead of having to use two lines ...
            Code:
                ARRAY SCAN myArray(), =Var TO iHit 
                IF iHit THEN 
                 ....
            It could make some code a little easier to understand

            Code:
              IF MEMBER (color_choice, "BLUE", "GREEN", "YELLOW") THEN 
                  message "Yes, you can have it in that color...
              .....
            MCM
            Michael Mattias
            Tal Systems (retired)
            Port Washington WI USA
            [email protected]
            http://www.talsystems.com

            Comment


            • #7
              John, if you don't mind using pointers, this is very fast. Concise? Well, usage-wise it is: IF unitIsDate(unit) THEN ...do things... ELSE EXIT FUNCTION.

              Code:
              'unitIsDate() function returns 1 if 1st 2 chars match, 0 if not.
              'showed a 9x speed improvement over SELECT CASE
              #COMPILE EXE
              #DIM ALL
              
              FUNCTION unitIsDate(unit AS STRING) AS LONG
                 STATIC unitPtr, datePtr, searchPtr AS WORD PTR
                 STATIC ii AS LONG, dateStr AS STRING
              
                 IF datePtr = 0 THEN                     'only create the date string info once.
                    dateStr = "yrYryRYRmoMomOMOdyDydYDY" 'this saves time on subsequent calls
                    datePtr = STRPTR(dateStr)
                 END IF
                 unitPtr = STRPTR(unit)
                 searchPtr = datePtr
              
                 FOR ii = 1 TO 12
                    IF @unitPtr = @searchPtr THEN        'do the 1st 2 characters of unit match any in the date string?
                       FUNCTION = 1                      'if so, function = 1
                       EXIT FUNCTION
                    END IF
                    INCR searchPtr
                 NEXT
              
                 FUNCTION = 0
              
              END FUNCTION
              
              'test code below:
              FUNCTION PBMAIN () AS LONG
                 LOCAL ii, good AS LONG, unit AS STRING, t AS QUAD
              '   goto jm             'uncomment here to test your original technique
                 TIX t
                 FOR ii = 1 TO 1000000
                    IF (ii AND 7) = 0 THEN unit = "mo" ELSE unit = "om"
                    IF unitIsDate(unit) THEN INCR good
                 NEXT
                 TIX END t
                 ? STR$(good) & STR$(t)
                 EXIT FUNCTION
              
              jm:
                 TIX t
                 FOR ii = 1 TO 1000000
                    IF (ii AND 7) = 0 THEN unit = "mo" ELSE unit = "om"
                    SELECT CASE UCASE$(LEFT$(Unit, 2))
                    CASE "YR","MO","DY"
                       INCR good
                    CASE ELSE
                       EXIT SELECT
                    END SELECT
                 NEXT
                 TIX END t
                 ? STR$(good) & STR$(t)
              END FUNCTION            'empty:99m   fcn:277m  case:1703 so 178 vs. 1604, function is 9x more concise

              Comment


              • #8
                If "concise" is to mean "fast" then:
                Code:
                     DIM a&(0) AT STRPTR(unit)
                     b&=a&(0) AND &hdfdf
                     IF b&=&h4f4d OR b&=&h5259 OR b&=&h5944 THEN INCR good
                That also looks concise in terms of typed characters as well.

                Paul.
                Last edited by Paul Dixon; 3 Mar 2009, 01:04 PM.

                Comment


                • #9
                  Code:
                  DIM a&(0) AT STRPTR(unit)
                       b&=a&(0) AND &hdfdf
                       IF b&=&h4f4d OR b&=&h5259 OR b&=&h5944 THEN INCR good
                  That's the long way....
                  Code:
                    LOCAL pS2 AS STRING PTR * 2
                    pS2 = STRPTR(Unit) 
                    IF @pS2= "MO" or @pS2 = "YR" or @pS2 = "DA" THEN..
                  At least this you will understand when you see it next week.....

                  ... Or, you could make it an integer pointer, preset three equates ..
                  Code:
                  %DA_INT =  CVI("DA")    ' I don't think this is allowed, but these are the values
                  %MO_INT =  CVI("MO") 
                  %YR_INT =  CVI("YR")
                  .. and do integer compares....

                  MCM
                  Michael Mattias
                  Tal Systems (retired)
                  Port Washington WI USA
                  [email protected]
                  http://www.talsystems.com

                  Comment


                  • #10
                    Michael,
                    That's the long way....
                    Not so long. The line
                    Code:
                    b&=a&(0) AND &hdfdf
                    is important as it does the equivalent of UCASE$() on the characters in unit without disturbing its contents and then allows us to do only 3 compares instead of 6.
                    Of course, I didn't comment the code as it was supposed to be concise but sometimes concise isn't necessarily maintainable.

                    Paul.

                    Comment


                    • #11
                      So here are Bern's pointer and Paul's instant upper-case AND technique combined in a function with a couple comments to enhance maintainability, and BAM, 30x faster and concise to beat the band!
                      Code:
                      FUNCTION unitIsDatePD(unit AS STRING) AS LONG
                         STATIC unitPtr AS WORD PTR
                         STATIC ii AS WORD
                      
                         unitPtr = STRPTR(unit)
                         ii = @unitPtr AND &hdfdf                'capitalize unit so only 3 comparisons are needed
                                                                 'now check for each of 3 possibilities w/ short circuit...
                         IF ii = &h4f4d OR ii = &h5259 OR ii = &h5944 THEN FUNCTION = 1 '"MO" "YR" & "DY" in WORD form
                      
                      END FUNCTION

                      Comment


                      • #12
                        More brilliance than a roomful of floodlamps!

                        You guys are simply awesome! I'm always amazed at how an idea moves from "working" to "optimized" in so few steps!

                        At this time, I'm OK with the concise and "more readable" versions because the choices are so few. But when I have a lot more complex data and scanning to do, I will certainly try out these other techniques.

                        I must say, these posts have certainly got my appetite whetted for learning to use and master pointers. Now moved up on my list of things to study and use...


                        Added:
                        Michael, I like the idea of the MEMBER keyword, but I think in keeping with PB syntax, it would be more like:

                        Code:
                        IF MEMBER (myarray(), ANY v1, v2, v3, .... ) THEN
                        where the v1, v2, etc are the values I want compared.
                        Last edited by John Montenigro; 7 Mar 2009, 04:30 PM.

                        Comment

                        Working...
                        X