Wednesday, December 14, 2022

RPG concatenation BiF for arrays

I wrote earlier about a new Built in Function, BiF, that makes it easier to concatenate variables or strings. Another addition to the RPG language in the fall Technology Refreshes, IBM i 7.5 TR1 and 7.4 TR7, is another BiF to concatenate elements from an array.

The syntax of %CONCATARR BiF is very similar to %CONCAT I wrote about before:

Result = %concatarr(<separator character(s)> : 
                    <array name>) ;

Let me jump to my first example. This is the RPG code for the first part of my example program:

01  **free
02  dcl-s VarArray varchar(10) dim(*auto:100) ;
03  dcl-s NbrArray packed(5:2) dim(*auto:10) ;
04  dcl-s FixedArray char(10) dim(100) ;
05  dcl-s String char(100) ;

06  VarArray = %list('Amy' : 'Beth' : 'Carol' : 'Dawn' : 'Enid') ;
07  String = %concatarr(', ' : VarArray) ;

Line 1: All my RPG code is now free (format).

Line 2: I am defining an array where its elements are variable character, VARCHAR. The *AUTO keyword denotes that it will be a variable length array, which will automatically extend when I add data to it, up to 100 elements.

Line 3: Another variable length array, but this one's elements are packed numeric.

Line 4: This is a more "traditional" array, fixed length character elements and 100 elements.

Line 5: This is the definition for the variable that will contain the results of the concatenation.

Line 6: I load the elements of the array using the %LIST BiF. As I am loading five values into the array, it will have five elements not 100.

Line 7: The %CONCATARR BiF concatenates the elements together and put the result in the variable String.

The result looks just the way I want it to:

> EVAL String
STRING =
      ....5...10...15...20...25...30...35...40...45...50...55...60 
 1   'Amy, Beth, Carol, Dawn, Enid                                '
61   '                                        '

Thanks to the variable length array that was simple. What about doing the same with the fixed sized array?

08  FixedArray = %list('Alan' : 'Ben' : 'Clint' : 'David' : 'Elvis') ;
09  String = %concatarr(', ' : FixedArray) ;

Line 8: I load the first five elements using the %LIST BiF.

Line 9: Using the %CONCATARR with the fixed size array gives me the following result:

> EVAL String
STRING =
      ....5...10...15...20...25...30...35...40...45...50...55...60 
 1   'Alan      , Ben       , Clint     , David     , Elvis     , '
61   '          ,           ,           ,     '

As the elements are all fixed character sized and there are 100 elements the result looks messy.

Fortunately I can use the %TRIMR BiF to remove the trailing blanks from all of the elements:

10  String = %concatarr(', ' : %trimr(FixedArray) ) ;

The result looks better for the values in the first five elements.

> EVAL String
STRING =
      ....5...10...15...20...25...30...35...40...45...50...55...60 
 1   'Alan, Ben, Clint, David, Elvis, , , , , , , , , , , , , , , '
61   ', , , , , , , , , , , , , , , , , , , , '

I don't want the unused elements in my string. My solution may look complicated, but it is really not. I am just combining BiFs together in one statement.

I will need the following BiFs:

  • %CONCATARR:  You should know what that does by now
  • %TRIMR:  Remove trailing blanks from a string
  • %SUBARR:  Substring a number of elements from an array
  • %LOOKUP:  Find the first element in an array that is equal to test value

My statement looks like:

11  String = %concatarr(', ' :
12                      %trimr(%subarr(FixedArray :
13                        1 :
14                        %lookup(' ':FixedArray:1) -1))) ;

Line 11: Is already familiar.

Line 12: I have the %TRIMR to remove the trailing blanks from the %SUBARR that just extracts the used elements from the fixed array.

Line 13: The array substring starts at the first element.

Line 14: To determine the last used element I use the %LOOKUP. I am looking for a blank element, starting from the first position. When I find it I subtract one to get the last used element.

The result is exactly what I wanted:

> EVAL String
STRING =
       ....5...10...15...20...25...30...35...40...45...50...55...60 
 1   'Alan, Ben, Clint, David, Elvis                              '
61   '                                        '

If I had a random list of values that I wanted to concatenate in a sorted order I would need to use the SORTA operation code. I would do it like:

15  %elem(VarArray) = 0 ;
16  VarArray = %list('Zach' : 'Mike' : 'Xavier' : 'Will' : 'Jim') ;
17  sorta VarArray ;
18  String = %concatarr(', ' : VarArray) ;

Line 15: I reset the number of elements in the variable length array to zero, as my new list may have more or less elements than what it contains now.

Line 16: I load the array using the %LIST BiF.

Line 17: I sort the array in the default, ascending, order.

Line 18: Then I concatenate the array into String.

The result is:

> EVAL String
STRING =
      ....5...10...15...20...25...30.
 1   'Jim, Mike, Will, Xavier, Zach

My final example is with a numeric array, which is defined on line 3.

19  NbrArray = %list(5.03 : 3.12 : 8.97 : 7.31 : 15) ;
20  String = %concatarr(', ' : %char(NbrArray) ) ;

Line 19: Using %LIST to load the values into the array.

Line 20: It is not possible to concatenate numbers, therefore, I need to convert the arrays elements to character using the %CHAR BiF.

The result is:

> EVAL String
STRING =
      ....5...10...15...20...25...30...35...40...45...50...55...60 
 1   '5.03, 3.12, 8.97, 7.31, 15.00                               '
61   '                                        '

These examples show that %CONCATARR BiF is another useful addition to the RPG language.

 

You can learn more about the RPG %CONCATARR BiF from the IBM website here.

 

This article was written for IBM i 7.5 TR1 and 7.4 TR7.

4 comments:

  1. Hi Simon,
    As always, a great post.

    Two small typos though:-
    "Line 2: I am defining an array where its elements are variable character, VARCHAR. The INZ keyword denotes that it will be a variable length array"

    Should be "Line 2: I am defining an array where its elements are variable character, VARCHAR. The *auto keyword denotes that it will be a variable length array"

    "These examples show that %CONSTARR BiF is another useful addition to the RPG language."

    Should be "These examples show that %CONCATARR BiF is another useful addition to the RPG language.

    ReplyDelete
    Replies
    1. Oops. Thank you for bringing those to my attention. I have made the corrections.

      Delete
  2. I guess this widely known but new bifs fail validation in SEU. This one does.

    ReplyDelete
    Replies
    1. As SEU has not be enhanced since the 1990s everything modern fails its validation.
      You need to turn off the validation in SEU, that way you do not get the warnings that the code is invalid. Rely on the compile listings to identify what you have entered incorrectly.
      Read this.

      Delete

To prevent "comment spam" all comments are moderated.
Learn about this website's comments policy here.

Some people have reported that they cannot post a comment using certain computers and browsers. If this is you feel free to use the Contact Form to send me the comment and I will post it for you, please include the title of the post so I know which one to post the comment to.