04
Mon, Nov
6 New Articles

Working With Arrays and Tables, Part II

General
Typography
  • Smaller Small Medium Big Bigger
  • Default Helvetica Segoe Georgia Times

Building on Last Month's Basics

by Roger Pence

In last month's issue of Midrange Computing, we took a beginning look at tables and arrays. That article focused on defining the different types of tables and arrays and ways to load them with data. This month, we'll dig a little deeper and look at several advanced ways of manipulating array data.

There are six sample programs accompanying this month's article. They are all very short and no test data is required. To load and run any of them, after typing and compiling them, use:

 
 // LOAD  
 // RUN 

While the "user-interface" for these programs certainly isn't SAA compliant, you'll get the idea.

Array Specific Operation Codes

RPGII has four array-specific operation codes. Last month, we covered XFOOT, the operation code to sum the value of all elements in a numeric array into a specified field. The other three are SORTA, LOKUP, and MOVEA. Let's take a closer look at each.

The SORTA Operation

SORTA is an array-specific operation code that sorts all elements of an array in ascending or descending order. While there are surely other reasons why you might want an array sorted, SORTA is generally used to ensure that the elements of an array are in the appropriate order for the LOKUP operation code (more on this in a moment).

Column 45 of the array E spec is used to describe the sequence of an array (a "D" indicates the array should be in descending order, an "A" indicates the array should be in ascending order). If no sequence is specified, SORTA sorts the array in ascending order. The code in 1 would sort array ARRY in descending order.

Column 45 of the array E spec is used to describe the sequence of an array (a "D" indicates the array should be in descending order, an "A" indicates the array should be in ascending order). If no sequence is specified, SORTA sorts the array in ascending order. The code in Figure 1 would sort array ARRY in descending order.

If the E spec's column 45 had been blank or an "A", array ARR would have been sorted in ascending order.

For execution-time arrays (an array explicitly loaded with data from your Input or Calc specs), column 45 merely serves as a flag for SORTA to determine the order in which the array should be sorted. But column 45 is really more than a flag for SORTA--an entry in column 45 also tells RPG that the sequence of the array should be checked as it is loaded. Since no data is implicitly loaded for an execution-time array, RPG politely reminds you with a warning error that no sequence checking will be performed for that array. Don't worry, this is just a case of RPG being over-protective. In this case, you only want the entry in column 45 to control the order in which SORTA performs the sort.

If sequence checking is specified for compile-time arrays (arrays loaded with data statements from the source code) or for pre-execution time arrays (arrays implicitly loaded from disk files), the order of the data in the array is checked as it is loaded. If the order is out of sequence as the array is being loaded, a run-time error occurs. It would sure be nice if RPG let these arrays come into the program in jumbled-up order, then allowed you to use SORTA to put them in the right order before you use them, but that is not the case. It is your responsibility to make sure the data for these two types of arrays is in the appropriate sequence before the program starts.

The LOKUP Operation

LOKUP searches an array for a specific value. We saw last month how the LOKUP operation code is used to search for a value in a table (or a pair of tables). Using the LOKUP operation code with arrays requires that:

Factor 1 defines the search value--the value being searched.

Factor 2 defines the array name being searched, and optionally, a beginning array index element.

Unlike table look-ups, factor 3 isn't used with array look-ups.

The resulting indicator in columns 54-59 controls how the look-up is performed. If the array is not sequenced, LOKUP can be used to find a value in the array equal to the search value. To find an equal value, use an indicator in columns 58-59 (equal). If the array is sequenced, either as a result of being loaded that way or having been put in that order with SORTA, LOKUP can also be used to search for:

A value that is greater than the search value by using an indicator in columns 54-55 (high).

A value greater than or equal to the search value by using indicators in columns 54-55 and in 58-59 (high and equal).

A value that is less than the search value by using an indicator in columns 56-57 (low).

A value less than or equal to the search value by using indicators in columns 56-57 and in 58-59 (low and equal).

The RPG manual and some RPG error messages corroborate that anything other than an equal LOKUP requires sequence checking. But RPG is really a little wishy-washy about enforcing this rule, and we'll see an example of bending it to our advantage when we discuss program ARRAY3.

LOKUP really has two "modes" when used with arrays. If an array name without an index is specified in factor 2, LOKUP reports (using the indicator you specified) if the search was successful. For example, the code in 2 would turn on indicator 50 if the value 5 was in any element of array ARR.

LOKUP really has two "modes" when used with arrays. If an array name without an index is specified in factor 2, LOKUP reports (using the indicator you specified) if the search was successful. For example, the code in Figure 2 would turn on indicator 50 if the value 5 was in any element of array ARR.

What if that is not enough information? Not only do you need to know if it's there, but you also need to know where it is. LOKUP provides a way to do this by using the array name with an index. 3 shows an example. This would not only turn on indicator 50 if the value 5 is in the array ARR, but it would also put the element number containing value 5 in X.

What if that is not enough information? Not only do you need to know if it's there, but you also need to know where it is. LOKUP provides a way to do this by using the array name with an index. Figure 3 shows an example. This would not only turn on indicator 50 if the value 5 is in the array ARR, but it would also put the element number containing value 5 in X.

There are two things to be aware of when you use LOKUP in this manner:

1) LOKUP starts the look-up at the element of the specified array index. In the example above, X is set to 1 to start the search in the first element of ARR. Had X been set to 8, LOKUP would have looked for the value 5 in array ARR starting at element 8, disregarding the first 7 elements. This powerful feature is handy because it allows for subsequent searches of other occurrences of the search value. But it's also dangerous--if you forget to set the index value before you start the search, the look-up could return unreliable results.

2) If the LOKUP is successful, the number of the array elements matching LOKUP's criteria is returned in the index field used in factor 2. But, if the search is not successful, this index field is always set to 1. Therefore, you must always use the status of the resulting indicator to ensure the success of the look-up.

SORTA and LOKUP in Action

The sample program, ARRAY1, in 4 demonstrates using SORTA and LOKUP to find the element in an array that is greater than or equal to a specified value. When ARRAY1 starts, it prompts you for values for each of array ARR's 10 elements. After youUve entered these 10 values (you do not have to enter them in sequence), ARRAY1 uses SORTA to sort the array in ascending order. Then, a search is performed for the value you specified and the search results shown, until you enter a zero search value.

The sample program, ARRAY1, in Figure 4 demonstrates using SORTA and LOKUP to find the element in an array that is greater than or equal to a specified value. When ARRAY1 starts, it prompts you for values for each of array ARR's 10 elements. After youUve entered these 10 values (you do not have to enter them in sequence), ARRAY1 uses SORTA to sort the array in ascending order. Then, a search is performed for the value you specified and the search results shown, until you enter a zero search value.

To change ARRAY1 to search for an array element less than or equal to the search value, move indicator 50 in line 13 from columns 54-55 (greater than) to columns 56-57 (less than).

The MOVEA Operation

MOVEA is a very powerful array-specific operation code that can move numeric and alphameric data from fields to arrays, from arrays to fields, or from arrays to arrays. MOVEA is very flexible and provides several ways of moving data, but it does not allow the movement of data from an array to other positions of the same array--the arrays referenced in factor 2 and the result field must always be different arrays.

Data is moved by MOVEA on a byte-per-byte basis, starting at the leftmost position of factor 2 and the leftmost position of the result field. MOVEA stops moving data when either all bytes of factor 2 have been moved or until the last byte of the result field has been filled. 5 shows an example of using MOVEA to move the contents of a 15 character field to a 15 byte, one position element array. If ARR had been defined as having only 10 elements instead of 15, ARR would have the value "Indianapol".

Data is moved by MOVEA on a byte-per-byte basis, starting at the leftmost position of factor 2 and the leftmost position of the result field. MOVEA stops moving data when either all bytes of factor 2 have been moved or until the last byte of the result field has been filled. Figure 5 shows an example of using MOVEA to move the contents of a 15 character field to a 15 byte, one position element array. If ARR had been defined as having only 10 elements instead of 15, ARR would have the value "Indianapol".

Notice how MOVEA stopped moving data when it filled the last byte of ARR. Watch out for this data truncation--MOVEA does its work without regard for array boundaries and will simply assume you want the data chopped off. This is especially critical if youUre moving a numeric source into an alphameric target. If the target isn't sized correctly, you could lose the sign and perhaps some of the digits you meant to move.

MOVEA can also work with an array index to start a move at a particular spot in the array. 6 shows an example. Notice how the first four elements are still blank and the move started in the fifth element. The source data was truncated when the end of array ARR was reached.

MOVEA can also work with an array index to start a move at a particular spot in the array. Figure 6 shows an example. Notice how the first four elements are still blank and the move started in the fifth element. The source data was truncated when the end of array ARR was reached.

MOVEA can also move arrays into fields. Again, the entire array could be moved, or the move could start from a specific element. 7 shows an example. Note how MOVEA stopped moving data when it got to the end of the array ARR. Since it didn't move enough data to fill the last four bytes of FLD, they remain as they were before the MOVEA operation.

MOVEA can also move arrays into fields. Again, the entire array could be moved, or the move could start from a specific element. Figure 7 shows an example. Note how MOVEA stopped moving data when it got to the end of the array ARR. Since it didn't move enough data to fill the last four bytes of FLD, they remain as they were before the MOVEA operation.

MOVEA also allows moving data between arrays. In the example in 8, data is moved from arrays with elements of the same size, but each array has a different number of elements.

MOVEA also allows moving data between arrays. In the example in Figure 8, data is moved from arrays with elements of the same size, but each array has a different number of elements.

And again, with array to array moves, each array can optionally specify an index to indicate where the move should start. 9 illustrates. In this example, the move started from element 2 of array ARR2 and was moved to array AR1, starting with its third element.

And again, with array to array moves, each array can optionally specify an index to indicate where the move should start. Figure 9 illustrates. In this example, the move started from element 2 of array ARR2 and was moved to array AR1, starting with its third element.

In the next example (10), the array elements are different sizes, the array lengths are different, and the arrays are different types. Note how AR2 filled up before all the characters were moved.

In the next example (Figure 10), the array elements are different sizes, the array lengths are different, and the arrays are different types. Note how AR2 filled up before all the characters were moved.

Character Strings

Arrays are especially handy for manipulating character strings. Using the MOVEA operation, a field value can be moved into an array of 1 byte characters, allowing those characters to be manipulated. The modified array could then be moved back into the field with the MOVEA operation code. Three of the sample programs this month show examples of manipulating character strings using several of the concepts weUve discussed so far.

Flipping Two Fields

To be able to search and sort a file alphabetically, it is common to see master files which two name fields: one in the format for presentation purposes, and one in the format for indexing and sorting purposes. Sample program ARRAY2 in 11 offers a solution to this "doubled-up" field problem that requires only one name field. Given a name in the format ; (note the semicolon delimiting the first name from the last) ARRAY2 returns the name in the format . All indexing and sorting would be done on this field. Using the code in ARRAY2, the field would be "flipped" to the format for presentation purposes.

To be able to search and sort a file alphabetically, it is common to see master files which two name fields: one in the format for presentation purposes, and one in the format for indexing and sorting purposes. Sample program ARRAY2 in Figure 11 offers a solution to this "doubled-up" field problem that requires only one name field. Given a name in the format ; (note the semicolon delimiting the first name from the last) ARRAY2 returns the name in the format . All indexing and sorting would be done on this field. Using the code in ARRAY2, the field would be "flipped" to the format for presentation purposes.

ARRAY2 uses three subroutines

$$FLIP: Returns a flipped name, using the semicolon as the delimiter. If the name doesn't have a semicolon in it, the name is returned unmodified.

$$AT: Returns the position of character in a string. If the character isn't found, a -1 is returned.

$$FFR: Returns the position of the first non-blank character from the right-hand end of a string. If the string is empty, a zero is returned.

To run ARRAY2, type a name in the format ; (SMITH;BOB) and watch ARRAY2 flip that name for you. Also try using a name without a semicolon (SMITH APPLIANCE) and a name with an embedded comma (SMITH, Jr;Bob) to see how ARRAY2 handles those.

Right or Left Justify a String

The sample program, ARRAY3, in 12, right or left justifies a string. Try typing strings with leading blanks and strings with trailing blanks to see what ARRAY3 does with them.

The sample program, ARRAY3, in Figure 12, right or left justifies a string. Try typing strings with leading blanks and strings with trailing blanks to see what ARRAY3 does with them.

Note that it makes a call to the previously mentioned subroutine $$FFR, to find the first non-blank position from the right-hand end of the string. Several of the subroutines included in these sample programs are designed to be "toolbox" subroutinesQreusable subroutines, separately maintained in their own source files. If youUre familiar with the /COPY concept and compiling programs with the AUTOC procedure, I encourage you to use these subroutines in this fashion (this "toolbox" concept was covered in detail in the November 1988 issue of DataNetwork (now Midrange Computing). If you're not, don't worry about it right now, remove the /COPY line and just use your editor's INCLUDE feature to pull the needed subroutine in.

As we mentioned earlier, by the book, anything but an equal LOKUP requires sequence checking. Line 25 of program ARRAY3 searches an array--without sequence checkingQfor the first non-blank position. This LOKUP causes RPG to wince a little and issue warning error #198, reminding you about sequence checking. Don't worry, this LOKUP does work to find the first non- blank character in an arrayQwithout sequence checking. The moral of the story: just because the rules say it can't be done, doesn't really mean it can't. When you were a kid, how many times did your mother tell you not to eat in the family room? How many times have you done so since without being struck by lightning?

Search and Replace a Character

Given a string, a search character, and a replacement character, the sample program ARRAY4 (13) will search and replace every occurrence of the search character with the replacement character. This program makes a call to $$AT to find the position of a character in a string, so again you need to put that subroutine in this program with your favorite method (remember to remove the /COPY line if you INCLUDE the subroutine).

Given a string, a search character, and a replacement character, the sample program ARRAY4 (Figure 13) will search and replace every occurrence of the search character with the replacement character. This program makes a call to $$AT to find the position of a character in a string, so again you need to put that subroutine in this program with your favorite method (remember to remove the /COPY line if you INCLUDE the subroutine).

Two Dimensional Arrays

RPG's support of arrays is limited to single-dimensional arrays. That is, an RPG array may represent one column and many rows, or many rows and one column, but not many of both. In some cases, it is desirable to "trick" RPG into thinking it can support two-dimensional arrays. Here are two ways to simulate two-dimensional arrays in RPG.

Two-Dimensional Arrays-- Calculation Method

Consider the egg crate example we used last month. An egg crate is a good example of a two-dimensional arrayQit has two rows, with each row containing six columns. If our egg crate was filled with a dozen Easter eggs, sample program ARRAY5 (14) shows you what color Easter egg is in any given row and column. After asking you what row and column you want, ARRAY5 displays the color of the egg at those coordinates.

Consider the egg crate example we used last month. An egg crate is a good example of a two-dimensional arrayQit has two rows, with each row containing six columns. If our egg crate was filled with a dozen Easter eggs, sample program ARRAY5 (Figure 14) shows you what color Easter egg is in any given row and column. After asking you what row and column you want, ARRAY5 displays the color of the egg at those coordinates.

Given the desired row and column, and the total columns in the two- dimensional array, the subroutine $$2DAR calculates what the actual array element number is that matches those coordinates and returns that number in the field @R. To keep this program short, no error checking is performed in $$2DAR. To make this concept really valid, you should add some very robust error checking to $$2DAR (check for logical row and column requests, etc). If an error occurs, $$2DAR should return a -1 in @R to indicate the error condition to the calling code.

While this two-dimensional array trick has some real-world application, I've never really been comfortable with it. Without serious error trapping, it's possible for this technique to cause you more trouble that it's worth. Read on for an alternative method of implementing two-dimensional arrays.

Two-Dimensional Arrays With Nested Arrays

With RPG arrays, array elements cannot be other arrays. At least, that's what RPG thinks. Sample program ARRAY6 (15) shows a technique using the MOVEA operation code that allows an array to be an array of arrays. In program ARRAY6, array HLD is an array with 3000, 20-byte alphameric elements. Array ARR is an array with four, five-digit integer elements. Each element of HLD holds one entire ARR array, therefore, there are actually 3000 ARR arrays available in program ARRAY6! Thinking of the data two-dimensionally, there are 3000 rows available with each row having four columns.

With RPG arrays, array elements cannot be other arrays. At least, that's what RPG thinks. Sample program ARRAY6 (Figure 15) shows a technique using the MOVEA operation code that allows an array to be an array of arrays. In program ARRAY6, array HLD is an array with 3000, 20-byte alphameric elements. Array ARR is an array with four, five-digit integer elements. Each element of HLD holds one entire ARR array, therefore, there are actually 3000 ARR arrays available in program ARRAY6! Thinking of the data two-dimensionally, there are 3000 rows available with each row having four columns.

When program ARRAY6 starts, it asks which copy of array ARR (of the 3000 available) you want to work with. ARRAY6 then asks if you want to add to (A) or show (S) the values in the selected array. When you reply "A", ARRAY6 prompts you for four values to add to the corresponding elements of the currently selected copy of ARR. Use the "A" reply to put several values in several of the available ARR arrays, then use the RSS reply to see that they're really there and that theyUre being correctly incremented. Try entering some negative values to see that the sign of each number isn't lost in the shuffle.

With MOVEA's help, this technique makes the columns (the elements of the nested array) available without any arithmetic and with very little error checking. The MOVEA method offers a more straight-forward and a less error-prone way of implementing two-dimensional arrays in RPG than the previously discussed method.

Using Other Operation Codes

With Arrays

Having seen how SORTA, LOKUP, and MOVEA work with arrays, let's take a look at how some of the non-array specific operation codes work with arrays.

Any of the arithmetic operation codes (MULT, ADD, DIV, Z-ADD, Z-SUB, etc.) can be used with any numeric array or its individual elements. For example, the following code increments the value of the first element of array ARR by 1:

 
 C    ADD  1     ARR,1 

This code increments the value of ALL elements in array ARR by 1:

 
 C    ADD  1     ARR 

Notice that no array index is specified in the result field in the second example. Excluding the array index tells RPG to work on every element in the array. This is true for almost all of the arithmetic operation codes (we'll discuss an exception in a moment). When used with an array index, arithmetic operation codes modify that element only; when used without an index, they modify all elements in the array.

Consider an array with 12 nine-digit, two-decimal place numbers. Let's say you wanted to round all 12 elements to 7 digits with no decimal places. The code in 16 would do that.

Consider an array with 12 nine-digit, two-decimal place numbers. Let's say you wanted to round all 12 elements to 7 digits with no decimal places. The code in Figure 16 would do that.

Are Arrays Neat or What?

While most arithmetic operation codes work with an entire array or any individual element in the array, MVR is an exception. MVR, the arithmetic operation code to save the remainder of a division, will not work with all elements of an array at once. To save the remainders of array division, you'll have to use loop-processing as shown in 17.

While most arithmetic operation codes work with an entire array or any individual element in the array, MVR is an exception. MVR, the arithmetic operation code to save the remainder of a division, will not work with all elements of an array at once. To save the remainders of array division, you'll have to use loop-processing as shown in Figure 17.

An alternative method of array division with remainders was discussed in the November 1986 issue of DataNetwork.

You can also MOVE and MOVEL data into an array element or into an entire array. The code in 18 would set the first element of AR1 to an asterisk (*), and all 200 elements of AR2 to asterisks. MOVEL works the same way.

You can also MOVE and MOVEL data into an array element or into an entire array. The code in Figure 18 would set the first element of AR1 to an asterisk (*), and all 200 elements of AR2 to asterisks. MOVEL works the same way.

RPG III offers a feature called multiple-occurring data structures (IBMese for an array of data structures). Using the MOVE operation code with an appropriately sized array and data structure, you can mimic an array of data structures in RPG II (this method is a close cousin to the previously discussed MOVEA two-dimensional array technique).

In the example in 19, HLD is an array that holds 100 "occurrences" of a 32-byte data structure. By MOVEing data back and forth between HLD and the data structure, you can easily mimic an array of data structures. Note that with this construction, either the MOVE operation code or the MOVEA operation code could have been used--both work the same here.

In the example in Figure 19, HLD is an array that holds 100 "occurrences" of a 32-byte data structure. By MOVEing data back and forth between HLD and the data structure, you can easily mimic an array of data structures. Note that with this construction, either the MOVE operation code or the MOVEA operation code could have been used--both work the same here.

Miscellaneous Operation Codes

The four operation codes to move zone and digit portions back and forth (MHHZO, MHLZO, MLHZO, and MLLZO) also work on individual elements of an array or on all of the elements at once. Performing the operation on an array without referencing an index changes every element; specifying an index on the array will cause the operation to affect only the one element.

TESTB, TESTZ, BITOF, and BITON will not work on entire arrays, but may be used with individual elements of an array.

A Bigger Bag of Tricks!

A thorough knowledge of the power of RPG's table and array processing is a very important part of the expert RPG programmer's bag of tricks. In addition to the material we've covered in the last two months, tables and arrays are very thoroughly covered in Chapter 13 of the Programming with RPGII manual. Study that chapter, and fiddle with the sample programs and ideas from this two-part series--you'll need a bigger bag for your RPG tricks before you know it!


Working With Arrays and Tables, Part II

Figure 1 Sorting an array in descending order

 
  Figure 1: Sorting an array in descending order 
 
       6..10....+...20....+...30....+...40....+...50...+...60 
       E                    ARR        15 10 0D 
       C                     SORTAARR 

Working With Arrays and Tables, Part II

Figure 10 Moving different size arrays

 
  Figure 10: Moving different size arrays 
 
      6..10....+...20....+...30....+...40....+...50...+...60 
      E                    AR1         5  4 0 
      E                    AR2        16  1 
      C                     MOVEAAR1       AR2,3 
 
      Before MOVEA: 
 
      Array AR1: /0001/0002/0003/0004/0005/ 
      Array AR2: / / / / / / / / / / / / / / / / / 
 
      After MOVEA: 
 
      Array AR2: / / /0/0/0/1/0/0/0/2/0/0/0/3/0/0/ 

Working With Arrays and Tables, Part II

Figure 11 Flip a name

 
  Figure 11: Flip a Name 
 
  1...+...10....+...20....+...30....+...40....+...50...+...60 
  0001 H     064                            Col 75>    ARRAY2 
  0002  ** FLIP A NAME (JONES;BOB = BOB JONES) 
  0003 FCONIN   IP     79  79            KEYBORD 
  0004 FCONOUT  O      79  79            CRT 
  0005 E                    W1         30  1 
  0006 E                    W2         30  1 
  0007 C           'NAME'    KEY            NAME   30      LR 
  0008 C     NLR             MOVEANAME      W1 
  0009 C     NLR             EXSR $$FLIP 
  0010 C     NLR             MOVEAW1        NAME 
  0011  * 
  0012 C           $$FLIP    BEGSR 
  0013 C                     MOVE *BLANKS   W2 
  0014 C                     Z-ADD1         X       90 
  0015 C                     MOVE ';'       CHAR    1 
  0016 C                     EXSR $$AT 
  0017 C           X         IFNE -1 
  0018 C                     ADD  1         X 
  0019 C                     MOVEAW1,X      W2 
  0020 C                     SUB  1         X 
  0021 C                     MOVEA*BLANKS   W1,X 
  0022 C                     Z-ADD30        X 
  0023 C                     EXSR $$FFR 
  0024 C                     ADD  2         X 
  0025 C                     MOVEAW1        W2,X 
  0026 C                     MOVEAW2        W1 
  0027 C                     END 
  0028 C                     ENDSR 
  0029  * 
  0030 CSR         $$AT      BEGSR 
  0031 C           CHAR      LOKUPW1,X                     50 
  0032 C     N50             Z-ADD-1        X 
  0033 C                     ENDSR 
  0034  * 
  0035 CSR         $$FFR     BEGSR 
  0036 C           X         DOWNE0 
  0037 C           W2,X      IFNE *BLANK 
  0038 C                     GOTO $$FFRX 
  0039 C                     END 
  0040 C                     SUB  1         X 
  0041 C                     END 
  0042 C           $$FFRX    ENDSR 
  0043  * 
  0044 OCONOUT  D  1    NLR 
  0045 O                         NAME      35 
  1...+...10....+...20....+...30....+...40....+...50...+...60 

Working With Arrays and Tables, Part II

Figure 12 Right or Left justify a character string

 
  Figure 12: Right or Left Justify a Character String 
 
  1...+...10....+...20....+...30....+...40....+...50...+...60 
  0001 H     064                            Col 75>    ARRAY3 
  0002  ** RIGHT OR LEFT JUSTIFY A CHARACTER STRING 
  0003 FCONIN   IP     79  79            KEYBORD 
  0004 FCONOUT  O      79  79            CRT 
  0005 E                    W1         30  1 
  0006 E                    W2         30  1 
  0007 E                    RUL     1   1 30 
  0008 C           'NAME'    KEY            NAME   30      LR 
  0009 C           'R/L'     KEY            RORL    1      LR 
  0010 C                     MOVEANAME      W1 
  0011 C                     Z-ADD30        X       90 
  0012 C           RORL      CASEQ'L'       $$LJ 
  0013 C           RORL      CASEQ'R'       $$RJ 
  0014 C                     END 
  0015 C                     MOVEAW2        NAME 
  0016  ** 
  0017 CSR         $$LJ      BEGSR 
  0018 C                     MOVE *BLANKS   W2 
  0019 C                     Z-ADD1         X 
  0020 C           *BLANK    LOKUPW1,X                 50 
  0021 C                     MOVEAW1,X      W2 
  0022 C                     ENDSR 
  0023  ** 
  0024 C           $$RJ      BEGSR 
  0025 C                     Z-ADDX         HOLD    90 
  0026 C                     MOVEAW1        W2 
  0027 C                     MOVE *BLANKS   W1 
  0028 C                     EXSR $$FFR 
  0029 C           HOLD      SUB  X         X 
  0030 C                     ADD  1         X 
  0031 C                     MOVEAW2        W1,X 
  0032 C                     MOVEAW1        W2 
  0033 C                     ENDSR 
  0034  ** $$FFR SUBR HERE (INCL FROM ARRAY2 OR /COPY) 
  0035 C/COPY S,$$FFR 
  0036 OCONOUT  D  1    NLR 
  0037 O                         RUL       30 
  0038 OCONOUT  D  1    NLR 
  0039 O                         NAME      30 
  **  (RULER BAR) 
  1...+...10....+...20....+...30 
  1...+...10....+...20....+...30....+...40....+...50...+...60 

Working With Arrays and Tables, Part II

Figure 13 Earch and replace character string occurences

 
  Figure 13: Search and Replace Character String Occurences 
 
  1...+...10....+...20....+...30....+...40....+...50...+...60 
  0001 H     064                            Col 75>    ARRAY4 
  0002  ** SEARCH/REPLACE ALL OCCURRENCES OF CHAR IN A STRING 
  0003 FCONIN   IP     79  79            KEYBORD 
  0004 FCONOUT  O      79  79            CRT 
  0005 E                    W1         30  1 
  0006 C           'NAME'    KEY            NAME   30      LR 
  0007 C           'CHAR'    KEY            CHAR    1 
  0008 C           'SUB CHAR'KEY            SUBCHA  1 
  0009 C           NAME      IFNE *BLANKS 
  0010 C                     EXCPT 
  0011 C                     MOVEANAME      W1 
  0012 C                     Z-ADD1         X       90 
  0013 C                     EXSR $$AT 
  0014 C           X         DOWGT0 
  0015 C                     MOVE SUBCHA    W1,X 
  0016 C                     EXSR $$AT 
  0017 C                     END 
  0018 C                     MOVEAW1        NAME 
  0019 C                     EXCPT 
  0020 C                     END 
  0021  ** 
  0022  **   $$AT SUBR HERE (INCL FROM ARRAY2 OR /COPY) 
  0023 C/COPY S,$$AT 
  0024 OCONOUT  E  1 
  0025 O                         NAME      35 
  1...+...10....+...20....+...30....+...40....+...50...+...60 

Working With Arrays and Tables, Part II

Figure 14 Demonstration of a two-dimensional array

 
  Figure 14: Demonstration of a Two-Dimensional Array 
 
  1...+...10....+...20....+...30....+...40....+...50...+...60 
  0001 H     064                            Col 75>    ARRAY5 
  0002  ** TWO-DIMENSIONAL ARRAY DEMO 1 
  0003 FCONIN   IP     79  79            KEYBORD 
  0004 FCONOUT  O      79  79            CRT 
  0005 E                    AR1     6  12  7 
  0006 C           'ROW'     KEY            R       20     LR 
  0007 C           'COL'     KEY            C       20     LR 
  0008 C  NLR                Z-ADD6         TCOL    90 
  0009 C  NLR                Z-ADD2         TROW    90 
  0010 C  NLR                EXSR $$2DAR 
  0011 C  NLR                EXCPT 
  0012 C           $$2DAR    BEGSR 
  0013 C           TCOL      MULT R         R 
  0014 C           TCOL      SUB  C         C 
  0015 C           R         SUB  C         R 
  0016 C                     ENDSR 
  0017 OCONOUT  E  1 
  0018 O                                    5 'ROW=' 
  0019 O                         R     Z    8 
  0020 O                                   15 'COL=' 
  0021 O                         C     Z   18 
  0022 O                                   30 'COLOR=' 
  0023 O                         AR1,R     46 
  ** AR1 (THE EASTER EGGS!) 
  BLUE   YELLOW ORANGE BROWN  MAGENTAPINK 
  GREEN  RED    FUSCHIAPURPLE GOLD   BEIGE 
  1...+...10....+...20....+...30....+...40....+...50...+...60 

Working With Arrays and Tables, Part II

Figure 15 Two-dimensional array with nested arrays

 
  Figure 15: Two-Dimensional Array with Nested Arrays 
 
  1...+...10....+...20....+...30....+...40....+...50...+...60 
  0001 H     064                            Col 75>    ARRAY6 
  0002  ** 2-DIMENSIONAL ARRAYS WITH NESTED ARRAYS 
  0003 FCONIN   IP     79  79            KEYBORD 
  0004 FCONOUT  O      79  79            CRT 
  0005 E                    HLD      3000 20 
  0006 E                    ARR         4  5 0 
  0007 C           '1-3000 ?'KEY            NO      40 
  0008 C           'A OR S?' KEY            FS      1      LR 
  0009 C     NLR   FS        COMP 'AU                      50 
  0010 C     NLR 50          EXSR $$ADD 
  0011 C     NLR   FS        COMP 'S'                      51 
  0012 C     NLR 51          MOVEAHLD,NO    ARR 
  0013  ** 
  0014 CSR         $$ADD     BEGSR 
  0015 C                     MOVEAHLD,NO    ARR 
  0016 C                     DO   4         X       20 
  0017 C           X         KEY            VAL     50 
  0018 C                     ADD  VAL       ARR,X 
  0019 C                     END 
  0020 C                     MOVEAARR       HLD,NO 
  0021 C                     ENDSR 
  0022  ** 
  0023 OCONOUT  D  1     51NLR 
  0024 O                         ARR   L   60 
  1...+...10....+...20....+...30....+...40....+...50...+...60 

Working With Arrays and Tables, Part II

Figure 16 Rounding all elements of an array

 
  Figure 16: Rounding all elements of an array 
 
      6..10....+...20....+...30....+...40....+...50...+...60 
 
      E                    AR1        12  9 2 
      E                    AR2        12  7 0 
      C           AR1       MULT 1         AR2       H 

Working With Arrays and Tables, Part II

Figure 17 Saving remainders of array division

 
  Figure 17: Saving remainders of array division 
 
      6..10....+...20....+...30....+...40....+...50...+...60 
      E                    ARR        12  7 0 
      E                    REM        12  7 0 
      C                     DO   12        X       20 
      C           ARR,X     DIV  25        ARR,X 
      C                     MVR            REM,X 
      C                     END 

Working With Arrays and Tables, Part II

Figure 18 Using MOVE on an array

 
  Figure 18: Using MOVE on an array 
 
      6..10....+...20....+...30....+...40....+...50...+...60 
      E                    AR1       200  1 
      E                    AR2       200  1 
      C                     MOVE '*'       AR1,1 
      C                     MOVE '*'       AR2 

Working With Arrays and Tables, Part II

Figure 19 "Multiple occuring data structure"

 
  Figure 19: "Multiple-occurring data structure" 
 
      6..10....+...20....+...30....+...40....+...50...+...60 
      E                    HLD       100 32 
      I            DS 
      I                                        1  20 NAME 
      I                                       21  262RATE 
      I                                       27  320DATE 
      I                                        1  32 ARRDS 
      C** Some code to fill NAME, RATE, and DATE 
      C** and to select X, as the HLD array element in which 
      C** to store the ARRDS data structure. 
      C** 
      C                     MOVE ARRDS     HLD,X 
      C** 
      C** At some other point in the program, here is the 
      C** subsequent code to make the fields from the ARRDS data 
      C** structure previously stored in HLD,5 available: 
      C** 
      C                     MOVE HLD,5     ARRDS 
      C** 
      C** NAME, RATE, and DATE now have the value that was 
      C** previously stored in HLD,5 
      6..10....+...20....+...30....+...40....+...50...+...60 

Working With Arrays and Tables, Part II

Figure 2 Checking an array for a value

 
  Figure 2: Checking an Array for a Value 
 
       6..10....+...20....+...30....+...40....+...50...+...60 
       C           5         LOKUPARR                      50 

Working With Arrays and Tables, Part II

Figure 3 Finding the element containing the data

 
  Figure 3: Finding the element containing the data 
 
       6..10....+...20....+...30....+...40....+...50...+...60 
       C                     Z-ADD1         X 
       C           5         LOKUPARR,X                    50 

Working With Arrays and Tables, Part II

Figure 4 Sorting arrays and GT/EQ LOKUP

 
  Figure 4: Sorting Arrays and GT/EQ Lokup 
 
  1...+...10....+...20....+...30....+...40....+...50...+...60 
  0001 H     064                          Col 75>    ARRAY1 
  0002  ** DEMONSTRATE SORTING ARRAYS AND GT/EQ LOKUP 
  0003 FCONIN   IP     79  79            KEYBORD 
  0004 FCONOUT  O      79  79            CRT 
  0005 E                    ARR        10  5 0A 
  0006 C                     DO   10        X       40 
  0007 C           X         KEY 
  0008 C                     END 
  0009 C                     SORTAARR 
  0010 C           'SEARCH'  KEY            SEARCH  50 
  0011 C           SEARCH    DOWNE0 
  0012 C                     Z-ADD1         X 
  0013 C           SEARCH    LOKUPARR,X                50  50 
  0014 C                     EXCPT 
  0015 C           'SEARCH'  KEY            SEARCH 
  0016 C                     END 
  0017 C                     SETON                     LR 
  0018 OCONOUT  E  1 
  0019 O                         ARR   Z   70 
  0020 OCONOUT  E  1 
  0021 O                N50                12 'NOT FOUND' 
  0022 O                 50                12 'FOUND    ' 
  0023 O                 50      ARR,X Z   25 
  0024 O                 50      X     Z   30 
  1...+...10....+...20....+...30....+...40....+...50...+...60 

Working With Arrays and Tables, Part II

Figure 5 Moving a field's contents to an array

 
  Figure 5: Moving a Field's Contents to an Array 
 
      6..10....+...20....+...30....+...40....+...50...+...60 
      E                    ARR        15  1 
      C                     MOVEAFLD       ARR 
 
  Before MOVEA: 
 
  Field FLD: Indianapolis,IN 
  Array ARR: / / / / / / / / / / / / / / / / 
 
  After MOVEA: 
 
  ARR element number: 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 
  ARR element value: /I/n/d/i/a/n/a/p/o/l/i/s/,/I/N/ 

Working With Arrays and Tables, Part II

Figure 6 Starting a MOVEA at a particular element

 
  Figure 6: Starting a MOVEA at a Particular Element 
 
      6..10....+...20....+...30....+...40....+...50...+...60 
      E                    ARR        15  1 
      C                     MOVEAFLD       ARR,5 
 
  Before MOVEA: 
 
  Field FLD: Indianapolis,IN 
  Array ARR: / / / / / / / / / / / / / / / / 
 
  After MOVEA: 
 
  ARR element number: 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 
  ARR element value: / / / / /I/n/d/i/a/n/a/p/o/l/i/ 

Working With Arrays and Tables, Part II

Figure 7 Moving arrays into fields

 
  Figure 7: Moving arrays into fields 
 
      6..10....+...20....+...30....+...40....+...50...+...60 
      E                    ARR        15  1 
      C                     MOVEAARR,5     FLD    15 
 
      Before MOVEA: 
 
      Field FLD: XXXXXXXXXXXXXXX 
 
      Array ARR: /I/n/d/i/a/n/a/p/o/l/i/s/,/I/N/ 
 
      After MOVEA: 
 
      Element value:  a/n/a/p/o/l/i/s/,/I/N/X/X/X/X/ 

Working With Arrays and Tables, Part II

Figure 8 Moving data between arrays

 
  Figure 8: Moving data between arrays 
 
      6..10....+...20....+...30....+...40....+...50...+...60 
      E                    AR1         5  3 
      E                    AR2         3  3 
      C                     MOVEAAR2       AR1 
 
      Before MOVEA: 
 
      Array AR1: /AAA/BBB/CCC/DDD/EEE/ 
      Array AR2: /TTT/UUU/VVV/ 
 
      After MOVEA: 
 
      Array AR1: /TTT/UUU/VVV/DDD/EEE/ 

Working With Arrays and Tables, Part II

Figure 9 Array to array move with an index

 
  Figure 9: Array to array move with an index 
 
      6..10....+...20....+...30....+...40....+...50...+...60 
      E                    AR1         5  3 
      E                    AR2         3  3 
      C                     MOVEAAR2,2     AR1,3 
 
      Before MOVEA: 
 
      Array AR1: /AAA/BBB/CCC/DDD/EEE/ 
      Array AR2: /TTT/UUU/VVV/ 
 
      After MOVEA: 
 
      Array AR1: /AAA/BBB/UUU/VVV/DDD/ 
ROGER PENCE

Roger Pence is ASNA's Product Evangelist. Roger has been in the IBM i midrange community for so long that Elvis was alive when he started. He has been with ASNA since 2000. Prior to joining ASNA, Roger was a technical editor for NEWS/400 and the author of the 400/Group's AS/400 and Windows newsletter.

BLOG COMMENTS POWERED BY DISQUS

LATEST COMMENTS

Support MC Press Online

$

Book Reviews

Resource Center

  • SB Profound WC 5536 Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application. You can find Part 1 here. In Part 2 of our free Node.js Webinar Series, Brian May teaches you the different tooling options available for writing code, debugging, and using Git for version control. Brian will briefly discuss the different tools available, and demonstrate his preferred setup for Node development on IBM i or any platform. Attend this webinar to learn:

  • SB Profound WP 5539More than ever, there is a demand for IT to deliver innovation. Your IBM i has been an essential part of your business operations for years. However, your organization may struggle to maintain the current system and implement new projects. The thousands of customers we've worked with and surveyed state that expectations regarding the digital footprint and vision of the company are not aligned with the current IT environment.

  • SB HelpSystems ROBOT Generic IBM announced the E1080 servers using the latest Power10 processor in September 2021. The most powerful processor from IBM to date, Power10 is designed to handle the demands of doing business in today’s high-tech atmosphere, including running cloud applications, supporting big data, and managing AI workloads. But what does Power10 mean for your data center? In this recorded webinar, IBMers Dan Sundt and Dylan Boday join IBM Power Champion Tom Huntington for a discussion on why Power10 technology is the right strategic investment if you run IBM i, AIX, or Linux. In this action-packed hour, Tom will share trends from the IBM i and AIX user communities while Dan and Dylan dive into the tech specs for key hardware, including:

  • Magic MarkTRY the one package that solves all your document design and printing challenges on all your platforms. Produce bar code labels, electronic forms, ad hoc reports, and RFID tags – without programming! MarkMagic is the only document design and print solution that combines report writing, WYSIWYG label and forms design, and conditional printing in one integrated product. Make sure your data survives when catastrophe hits. Request your trial now!  Request Now.

  • SB HelpSystems ROBOT GenericForms of ransomware has been around for over 30 years, and with more and more organizations suffering attacks each year, it continues to endure. What has made ransomware such a durable threat and what is the best way to combat it? In order to prevent ransomware, organizations must first understand how it works.

  • SB HelpSystems ROBOT GenericIT security is a top priority for businesses around the world, but most IBM i pros don’t know where to begin—and most cybersecurity experts don’t know IBM i. In this session, Robin Tatam explores the business impact of lax IBM i security, the top vulnerabilities putting IBM i at risk, and the steps you can take to protect your organization. If you’re looking to avoid unexpected downtime or corrupted data, you don’t want to miss this session.

  • SB HelpSystems ROBOT GenericCan you trust all of your users all of the time? A typical end user receives 16 malicious emails each month, but only 17 percent of these phishing campaigns are reported to IT. Once an attack is underway, most organizations won’t discover the breach until six months later. A staggering amount of damage can occur in that time. Despite these risks, 93 percent of organizations are leaving their IBM i systems vulnerable to cybercrime. In this on-demand webinar, IBM i security experts Robin Tatam and Sandi Moore will reveal:

  • FORTRA Disaster protection is vital to every business. Yet, it often consists of patched together procedures that are prone to error. From automatic backups to data encryption to media management, Robot automates the routine (yet often complex) tasks of iSeries backup and recovery, saving you time and money and making the process safer and more reliable. Automate your backups with the Robot Backup and Recovery Solution. Key features include:

  • FORTRAManaging messages on your IBM i can be more than a full-time job if you have to do it manually. Messages need a response and resources must be monitored—often over multiple systems and across platforms. How can you be sure you won’t miss important system events? Automate your message center with the Robot Message Management Solution. Key features include:

  • FORTRAThe thought of printing, distributing, and storing iSeries reports manually may reduce you to tears. Paper and labor costs associated with report generation can spiral out of control. Mountains of paper threaten to swamp your files. Robot automates report bursting, distribution, bundling, and archiving, and offers secure, selective online report viewing. Manage your reports with the Robot Report Management Solution. Key features include:

  • FORTRAFor over 30 years, Robot has been a leader in systems management for IBM i. With batch job creation and scheduling at its core, the Robot Job Scheduling Solution reduces the opportunity for human error and helps you maintain service levels, automating even the biggest, most complex runbooks. Manage your job schedule with the Robot Job Scheduling Solution. Key features include:

  • LANSA Business users want new applications now. Market and regulatory pressures require faster application updates and delivery into production. Your IBM i developers may be approaching retirement, and you see no sure way to fill their positions with experienced developers. In addition, you may be caught between maintaining your existing applications and the uncertainty of moving to something new.

  • LANSAWhen it comes to creating your business applications, there are hundreds of coding platforms and programming languages to choose from. These options range from very complex traditional programming languages to Low-Code platforms where sometimes no traditional coding experience is needed. Download our whitepaper, The Power of Writing Code in a Low-Code Solution, and:

  • LANSASupply Chain is becoming increasingly complex and unpredictable. From raw materials for manufacturing to food supply chains, the journey from source to production to delivery to consumers is marred with inefficiencies, manual processes, shortages, recalls, counterfeits, and scandals. In this webinar, we discuss how:

  • The MC Resource Centers bring you the widest selection of white papers, trial software, and on-demand webcasts for you to choose from. >> Review the list of White Papers, Trial Software or On-Demand Webcast at the MC Press Resource Center. >> Add the items to yru Cart and complet he checkout process and submit

  • Profound Logic Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application.

  • SB Profound WC 5536Join us for this hour-long webcast that will explore:

  • Fortra IT managers hoping to find new IBM i talent are discovering that the pool of experienced RPG programmers and operators or administrators with intimate knowledge of the operating system and the applications that run on it is small. This begs the question: How will you manage the platform that supports such a big part of your business? This guide offers strategies and software suggestions to help you plan IT staffing and resources and smooth the transition after your AS/400 talent retires. Read on to learn: