Announcement

Collapse
No announcement yet.

Multi-choice logic

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

  • John Montenigro
    replied
    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, 03:30 PM.

    Leave a comment:


  • John Gleason
    replied
    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

    Leave a comment:


  • Paul Dixon
    replied
    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.

    Leave a comment:


  • Michael Mattias
    replied
    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

    Leave a comment:


  • Paul Dixon
    replied
    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, 12:04 PM.

    Leave a comment:


  • John Gleason
    replied
    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

    Leave a comment:


  • Michael Mattias
    replied
    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

    Leave a comment:


  • Bern Ertl
    replied
    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, 09:32 AM.

    Leave a comment:


  • John Montenigro
    replied
    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!

    Leave a comment:


  • Brian Chirgwin
    replied
    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

    Leave a comment:


  • Paul Dixon
    replied
    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, 09:29 PM.

    Leave a comment:


  • John Montenigro
    started a topic Multi-choice logic

    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?
Working...
X