Is there a way to do associative arrays in REXX?
Asked Answered
B

2

7

I have some Perl code (for performance analysis) first developed under Linux which now needs to be ported to the mainframe. Apparently REXX is the scripting language of choice on that platform but this Perl script relies heavily on associative arrays (basically arrays where the index is a string).

Is there a way that in REXX? How would I code up something like:

$arr{"Pax"} = "Diablo";
$arr{"Bob"} = "Dylan";
print $arr{"Pax"} . "\n";
if (defined $arr{"no"}) {
        print "Yes\n";
} else {
        print "No\n";
}
Bottleneck answered 4/11, 2010 at 12:40 Comment(1)
+1 for a REXX question. Haven't thought about REXX since my OS/2 days.Trigger
D
13

You can use stem variables, not exactly like arrays but very similar

/* REXX */
NAME = PAX
ARRAY.NAME = "DIABLO"
NAME = BOB
ARRAY.NAME = "DYLAN"
NAME = 'PAX'
SAY "ARRAY.PAX " IS ARRAY.NAME
NAME = 'BOB'
SAY "ARRAY.BOB " IS ARRAY.NAME
NAME = 'SANDY'
SAY "ARRAY.SANDY " IS ARRAY.NAME
IF ARRAY.NAME = "ARRAY.SANDY" THEN SAY "ARRAY.SANDY IS EMPTY"

The above Rexx will print

ARRAY.PAX  IS DIABLO
ARRAY.BOB  IS DYLAN
ARRAY.SANDY  IS ARRAY.SANDY
ARRAY.SANDY IS EMPTY

They can also be compound like a.b.c A stem variable if empty will return itself. There is no way to iterate of a stem that does not use consecutive numbers as the index that I know of.

IBM Manual with reference to Stem variables

Perl is available as an extra free feature for ZOS IBM Ported Tools for z/OS

Daisydaitzman answered 4/11, 2010 at 14:48 Comment(0)
P
11

I just want to add a bit more to the answer given by Deuian. I agree, REXX stem variables are the answer.

Simple REXX variables default to their own name. For example:

/* REXX */
SAY X

will print "X" until X is assigned some other value:

/* REXX */
X = 'A'
SAY X

will print "A".

No big surprise so far. Stem variables are a bit different. The head of the stem is never evaluated, only the bit after the initial dot is.

To illustrate:

/* REXX */                                                           
X. = 'empty'   /* all unassigned stem values take on this value */
A. = 'nil'
B = 'A'        /* simple variable B is assigned value A */                                                      
X = 'A'        /* simple variable X is assigned value A */                                                      
SAY X.A        /* prints: empty */                                 
X.A = 'hello'  /* Stem X. associates value of A with 'hello' */
SAY X.A        /* prints: hello */                                   
SAY X.B        /* prints: hello */                                   
SAY X.X        /* prints: hello */                                   

Notice the X and the A stem names are not evaluated, however, the X and A variables appearing after them are. Some people find this a bit confusing - think about it for a while and it makes great sense.

The Z/OS version of REXX does not provide a natural way to iterate over a stem variable. The easiest way to do this is to build your own index. For example:

/* REXX */
X. = ''
DO I = 1 TO 10
  J = RANDOM(100, 500) /* Random # 100..500 */
  X.INDEX = X.INDEX J  /* concatinate J's with 1 space between */
  X.J = 'was picked'   /* Associate 'was picked' with whatever J evalauates to */
  END

DO I = 1 TO WORDS(X.INDEX) /* Number of blank delimited 'words' */
  J = WORD(X.INDEX, I)     /* Extract 1 'word' at a time */
  SAY J X.J                /* Print 'word' and its associated value */
  END

Pretty trivial but illustrates the idea. Just be sure that INDEX (or whatever name you choose) to hold the indexing names never pops up as an associative value! If this is a possibility, use some other variable to hold the index.

Last point. Notice each of my examples begins with /* REXX */ you may find that this needs to be the first line of your REXX programs under Z/OS.

Pantelegraph answered 4/11, 2010 at 20:0 Comment(3)
In addition to the above, you can find out if a variable has been set or not via the Symbol() function: X=1; Say Symbol('X') /* -> 'VAR' /; Say Symbol('Y') / -> 'LIT' (for 'literal') */Conner
I notice that all the examples are wholly uppercase. Rexx is case aware. The bit you have to remember is that uninitialized variables use their UPPERCASE name as their value. Thus x.a = 1 actually sets x.A to1. However, if c='a' then x.c sets x.a a completely separate stem leaf from x.A.Highpressure
@Wes Evaluation of compound symbols works as follows: 1) Stem name is folded to uppercase but not evaluated. 2) Tail elements (separated by dots) fold to upper case then evaluate as individual symbols. 3) Folded stem name plus evaluated tail symbols form a "new" symbol. 4) Evaluate "new" symbol as is (not folded). This evaluation yields the compound symbol value. Continuing with your example where c = 'a' and symbol a is unassigned, the compound symbols: x.c, x.C, X.c and X.C all evaluate to the same thing, similarly, x.a, x.A, X.a and X.A also evaluate to the same, but different thing.Pantelegraph

© 2022 - 2024 — McMap. All rights reserved.