ibmi-brunch-learn

Announcement

Collapse
No announcement yet.

Search for a value in an array

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

  • Search for a value in an array

    Hello,

    I initially had the following idea;

    Code:
    D X               S              2p 0                  
    D Array           S              3a   Dim(10)          
    
    C                   Move      'CDE'         Array(1)   
    C                   Move      'ABC'         Array(2)   
    C                   Move      'FGH'         Array(3)   
    C                   Move      'IJK'         Array(4)   
    C                                                      
    C                   Eval       X = %LookUp('G' : Array)
    C                                                      
    C     X             DSPLY                              
    C                   SETON                                        LR
    Upon testing the above X is always 0 and this transpires to be because %LOOKUP is looking for an exact match, which makes sense.

    The element positions are important, i.e. CDE need to be 1, ABC need to be 2 etc. so the only idea I come up with to get around this is the below, but I was wondering if anyone had a better idea? I'd love to be able to do the check in 1 line rather than 10+;

    Code:
    D X               S              2p 0                
    D Z               S              2p 0                
    D Found           S              1a                  
    D Array           S              3a   Dim(4)         
    
    C                   Move      'CDE'         Array(1) 
    C                   Move      'ABC'         Array(2) 
    C                   Move      'FGH'         Array(3) 
    C                   Move      'IJK'         Array(4) 
    C                                                    
    C                   Eval      X = 0                  
    C                   Eval      Z = 0                  
    C                   Eval      Found = 'N'            
    C                                                    
    C                   DoW       X <= 4 and Found = 'N' 
    C                                                    
    C                   Eval      X = X + 1              
    C                   Eval      Z = %SCAN('G':Array(X))
    C                                                                  
    C                   If        Z <> 0                               
    C                   Eval      Found = 'Y'                          
    C                   Leave                                          
    C                   Endif                                          
    C                                                                  
    C                   EndDo                                          
    C                                                                  
    C     X             Dsply                                          
    C                                                                  
    C                   SETON                                        LR

    I has to be in fixed format I'm afraid, the program I'm changing was written in 1989 (older than me!) and I personally don't like mixing free and fixed.

  • #2
    Well, it's not 1 line of code, but it is shorter:
    Code:
    D X               S              2p 0                
    D Array           S              3a   Dim(4)         
    
    C                   Move      'CDE'         Array(1) 
    C                   Move      'ABC'         Array(2) 
    C                   Move      'FGH'         Array(3) 
    C                   Move      'IJK'         Array(4) 
    
    C                   For       X = 1 to %elem(Array)                  
    C                   If        %SCAN('G':Array(X)) > 0
    C                   Leave                                          
    C                   Endif                                          
    C                   Endfor                                          
    
    C     X             Dsply                                          
    
    C                   SETON                                        LR

    Comment


    • #3
      Thanks Brian, that looks 100 times better.

      Comment


      • #4
        Your problem as you have determined is that you can't search for a partial string like this. OK - so it has to be in fixed (which frankly is a silly requirement but I guess one imposed on you) but why use MOVE? If you use EVAL at least it can be easily converted should the powers-that-be ever decide to enter the 21st century.

        Are you always searching for the first character? Or trying to find it anywhere in the array - which is what your solution suggests. But having C in two groups in that case makes no sense - which is the "right answer?

        I can think of several solutions if you are searching the whole string.

        Here's one variant:

        Code:
             D Values          DS
             D                                3a   Inz('CDE')
             D                                3a   Inz('ABC')
             D                                3a   Inz('FGH')
             D                                3a   Inz('IJK')
             D Array                          1a   Dim(12) Overlay(Values)
        
             C
             C                   Eval       X = %LookUp('G' : Array)
             C                   Eval       X = ( X + 2 ) / 3
        This solution assumes that the codes are always in groups of three of course. If I was dealing with groups that could vary in length I might use an approach like this where each letter has an associated code number.

        Code:
             D Values          DS
             D                                  24a   Inz('C1D1E1A2B2C2....')
             D Array                                Dim(12) Overlay(Values)
             D     code                        1a  Overlay(Array) 
             D     group                      1a  Overlay(Array: *next)
        
        
             C                   Eval       I = %LookUp('G' : code)
             C                   Eval       X = code(I)
        That's my fixed form coding done for the year - yuck.

        Comment


        • #5
          You seem to be going out of your way to meet the technical limitations of RPG III. This would be so much simpler if you didn't need to comply with those old limitations... You don't need an array or data structure or multiple move operations. You can just do this:


          Code:
          dcl-s data char(12);
          data = 'CDEABCFGHIJK';
          X = %scan('G': data);
          You can even do that in fixed format code on V3R1!

          Code:
          D data            s             12a                 
          c                   eval      data = 'CDEABCFGHIJK'
          c                   eval      x = %scan('G': data)
          If you want (in either of the above) you can use INZ to set the string of letters rather than a separate assignment, so either of these examples could be just 2 lines of code.

          Is there a good reason to keep it compatable with RPG III?

          Comment


          • #6
            Originally posted by Scott Klement View Post
            <snip>

            Is there a good reason to keep it compatable with RPG III?
            There's never a GOOD reason Scott - but many millions of bad ones!

            I was tempted to respond as you did but figured it was time for my annual fixed format foray!

            Comment


            • #7
              Thanks for the replies here.

              It's fixed because it was written in 1989 and I personally don't like mixing fixed and free, am I the only one?

              Here's an example of what it's doing;

              STRING is 8a, ARRAY is 1a dim(8)

              Code:
              C                     MOVEASTRING   ARRAY    
              C*                                                    
              C                     DO   8         C                
              C                     SETOFF                        10
              C                     SETOFF                        11
              C                     SETOFF                        12
              C                     SELECT                           
              C           ARRAY,C   WHEQ 'A'                        
              C                     SETON                         10
              C           ARRAY,C   WHEQ 'B'                        
              C                     SETON                         11
              C           ARRAY,C   WHEQ 'C'                        
              C                     SETON                         12
              C                     ENDSL
              C   10                MOVE '5'       ARRAY,C
              C   11                MOVE '2'       ARRAY,C
              C   12                MOVE '9'       ARRAY,C
              C                     END
              So it looks through the STRING and converts any character values to numeric - fyi there is a "WHENEQ" for every letter of the alphabet... so I wanted to improve it.

              The numeric values are 0-9 - my initial idea was to group them up, put them in an array element represents their number and use lookup to find the array element but lookup didn't work how I expected.

              This is what I ended up with;

              EvalR drops any leading digits, i.e. when it finds K at position 15, it ends up as 5 not 15.

              Code:
              D X               S              2p 0                                      
              D Array           S              1a   Dim(4)                               
              D SerialChk       S             35a   Inz('DBMFAHNECPJIRXKLSUGYT-V-Q+      
              D                                          O-Z------W')                    
              
              C                   MoveA     'AKQW'        Array                     
              
              C                   For       X = 1 to %Elem(Array)                        
              C                   If        %Scan(Array(X) : SerialChk) > 0              
              C                   EvalR     Array(X) = %Char(%Scan(Array(X) : SerialChk))
              C                   Endif                                                  
              C                   EndFor                                                 
              
              C                   SETON                                        LR
              Looks a lot better, so thanks for the advice.

              Comment


              • #8
                Re your "mixing" comment. I don't like mixing fixed and fee for a one line change - although now that you no longer have to do /free /end-free it isn't the visual distraction it was so I'm far less concerned about it.

                Personally I always convert any code that needed a significant maintenance change to at least "real" RPG IV - the original code you show is really "stretched out" RPG III. e.g the WHENEQ etc.

                Personally I still would handle this with matching arrays which was one of the ideas I floated. The problem with any code like this (and indeed my divide by 3 version) is that the intent of the code is far from obvious. In your case the EVALR just adds to the confusion. If you have two arrays - one with the alpha and the other with the matching numeric value as I demonstrated above the intent is I think much clearer. i.e. Lookup this letter and substitute the matching number.

                Comment


                • #9
                  OK, so now that I know what the problem actually is, I can solve it in one line of code:

                  Code:
                  D Alpha           C                   Const('DBMFAHNECPJIRXKLSUGYTVQOZW')
                  D Number          C                   Const('12345678901234567890123456')
                  D String          S              8a
                  D NewString       S                   Like(String)
                  
                  
                  
                  C                   Xlate     NewString = %Xlate(Alpha:Number:String)

                  Comment


                  • Brian Rusch
                    Brian Rusch commented
                    Editing a comment
                    I can't edit my posts, so this will have to do. The first Xlate should have been an Eval.

                • #10
                  I _always_ forget Xlate Brian - thanks for the reminder.

                  Comment


                  • #11
                    Your welcome, Jon. One other variation if you wanted to put the translated string back into itself:
                    Code:
                    C                   Eval      String = %Xlate(Alpha:Number:String)

                    Comment


                    • #12
                      The reason I'm leaving it is mainly time, it does alot of stuff and it would take me, an inexperienced programmer, a long time to convert it... so I'll just patch it up and send it on.

                      I did explain what the EvalR was doing in the comments, I just left them out of the code.

                      I am shocked that xlate can do all this on one line... I'll deffo use that instead, thanks.

                      Comment


                      • RDKells
                        RDKells commented
                        Editing a comment
                        leaving it fixed*

                    • #13
                      Have setup the XLATE and tested it, worked a charm and made 100+ lines of code redundant.

                      This has definitely taught me something; keep it simple. Just because a program is doing something in a complicated manner doesn't mean your improvements need to follow a similar process. I was trying to loop through an array and convert things and stuff, because the program was doing it that way...

                      I guess there are many ways to skin a cat but the XLATE suggestion is just so straightforward and clear in what its doing - no messing around with arrays and loops!

                      It's crazy the advancements of RPG, when you look at it, someone sat and wrote 100+ lines of code to achieve that in 1989 (longer ago than I've been alive), unknowing that in a few years it could be achieved in 1 line.

                      Again; thanks for the time you took to help me out peeps.

                      Comment


                      • #14
                        Now you're learning! Winston Churchill (although not the originator of the idea) had it right when he said ?Those who fail to learn from history are doomed to repeat it.?. It is a good idea to understand _why_ things were done the way they were and in doing so facilitate improving them - as you have just done.

                        If you want to fill in your history you could read this bit http://ibmsystemsmag.com/blogs/ideve...oming-of-age-/ that I wrote back in 2015. That piece raised many questions and as a result I published a "History of RPG IV" series all of which are linked here: https://systemideveloper.com/blogs/p...rpg-published/

                        Want to know what is truly depressing? As best I can recall XLATE was available in the version of RPG available at the time this code was first written! It looks like the programmer may have had a System/36 RPG II background.

                        Comment


                        • RDKells
                          RDKells commented
                          Editing a comment
                          Words to live by.

                          I'll certainly have XLATE in my mind at a later date, it's not just about using the right tools for the right jobs it's also knowing said tools exist in the first place.

                          I've book marked those pages for a read later on.

                          That is depressing! It could be worse than than, I can justimagine them writing out the 100 lines of code, gently sobbing into their 1989 equivalent of redbull, already knowing they could do this in 1 line if the client just upgraded their O/S to a version that had XLATE... lol.
                      Working...
                      X