Each of the arrays we've considered thus far have been defined, by default, to have a lower bound of 1 and an upper bound which equals the number of elements in the array's dimension. For example, the array pennstate:
ARRAY pennstate(4) nittany lions happy valley;
has a lower bound of 1 and an upper bound of 4. In this section, we'll look at three examples that concern the bounds of an array. In the first example, we'll use the DIM function to change the upper bound of a DO loop's index variable dynamically (rather than stating it in advance). In the second example, we'll define the lower and upper bounds of a one-dimensional array to create a bounded array. In the third example, we'll use the LBOUND and HBOUND functions to change the lower and upper bounds of a DO loop's index variable dynamically.
Example 19.12 Section
The following program reads the yes/no responses of five subjects to six survey questions (q1, q2, ..., q6) into a temporary SAS data set called survey. A yes response is coded and entered as a 2, while a no response is coded and entered as a 1. Just four of the variables (q3, q4, q5, and q6) are stored in a one-dimensional array called qxs. Then, a DO LOOP, in conjunction with the DIM function, is used to recode the responses to the four variables so that a 2 is changed to a 1, and a 1 is changed to a 0:
DATA survey (DROP = i);
INPUT subj q1 q2 q3 q4 q5 q6;
ARRAY qxs(4) q3-q6;
DO i = 1 to dim(qxs);
qxs(i) = qxs(i) - 1;
END;
DATALINES;
1001 1 2 1 2 1 1
1002 2 1 2 2 2 1
1003 2 2 2 1 . 2
1004 1 . 1 1 1 2
1005 2 1 2 2 2 1
;
RUN;
PROC PRINT data = survey;
TITLE 'The survey data using dim function';
RUN;
Obs | subj | q1 | q2 | q3 | q4 | q5 | q6 |
---|---|---|---|---|---|---|---|
1 | 1001 | 1 | 2 | 0 | 1 | 0 | 0 |
2 | 1002 | 2 | 1 | 1 | 1 | 1 | 0 |
3 | 1003 | 2 | 2 | 1 | 0 | . | 1 |
4 | 1004 | 1 | . | 0 | 0 | 0 | 1 |
5 | 1005 | 2 | 1 | 1 | 1 | 1 | 0 |
First, note that although all of the survey variables (q1, ..., q6) are read into the survey data set, the ARRAY statement groups only 4 of the variables (q3, q4, q5, q6) into the one-dimensional array qxs. For example, qxs(1) corresponds to the q3 variable, qxs(2) corresponds to the q4 variable, and so on. Then, rather than telling SAS to process the array from element 1 to element 4, the DO loop tells SAS to process the array from element 1 to the more general DIM(qxs). In general, the DIM function returns the number of the elements in the array, which in this case is 4. The DO loop tells SAS to recode the values by simply subtracting 1 from each value. And, the index variable i is output to the survey data set by default and is therefore dropped.
Now, launch and run the SAS program. Then, review the output from the PRINT procedure to convince yourself that the program does indeed recode the four variables q3, q4, q5, and q6 as described.
Example 19.13 Section
As previously discussed and illustrated, if you do not specifically tell SAS the lower bound of an array, SAS assumes that the lower bound is 1. For most arrays, 1 is a convenient lower bound and the number of elements is a convenient upper bound, so you usually don't need to specify both the lower and upper bounds. However, in cases where it is more convenient, you can modify both bounds for any array dimension.
In the previous example, perhaps you find it a little awkward that the array element qxs(1) corresponds to the q3 variable, the array element qxs(2) corresponds to the q4 variable, and so on. Perhaps you would find it more clear for the array element qxs(3) to correspond to the q3 variable, the array element qxs(4) to correspond to the q4 variable, ..., and the array element qxs(6) to correspond to the q6 variable. The following program is similar in function to the previous program, except here the task of recoding is accomplished by defining the lower bound of the qxs array to be 3 and the upper bound to be 6:
DATA survey (DROP = i);
DATA survey2 (DROP = i);
INPUT subj q1 q2 q3 q4 q5 q6;
ARRAY qxs(3:6) q3-q6;
DO i = 3 to 6;
qxs(i) = qxs(i) - 1;
END;
DATALINES;
1001 1 2 1 2 1 1
1002 2 1 2 2 2 1
1003 2 2 2 1 . 2
1004 1 . 1 1 1 2
1005 2 1 2 2 2 1
;
RUN;
PROC PRINT data = survey2;
TITLE 'The survey data using bounded arrays';
RUN;
Obs | subj | q1 | q2 | q3 | q4 | q5 | q6 |
---|---|---|---|---|---|---|---|
1 | 1001 | 1 | 2 | 0 | 1 | 0 | 0 |
2 | 1002 | 2 | 1 | 1 | 1 | 1 | 0 |
3 | 1003 | 2 | 2 | 1 | 0 | . | 1 |
4 | 1004 | 1 | . | 0 | 0 | 0 | 1 |
5 | 1005 | 2 | 1 | 1 | 1 | 1 | 0 |
If you compare this program with the previous program, you'll see that only two things differ. The first difference is that the ARRAY statement here defines the lower bound of the qxs array to be 3 and the upper bound to be 6. In general, you can always define the lower and upper bounds of any array dimension in this way, namely by specifying the lower bound, then a colon (:), and then the upper bound. The second difference is that, for the DO loop, the bounds on the index variable i are specifically defined here to be between 3 and 6 rather than 1 to DIM(qxs) (which in this case is 4).
Now, launch and run the SAS program. Then, review the output from the PRINT procedure to convince yourself that the program does indeed re-code the four variables q3, q4, q5, and q6 just as in the previous program.
Example 19.14 Section
Now, there's still a little bit more that we can do to automate the handling of the bounds of an array dimension. The following program again uses a one-dimensional array qxs to recode four survey variables as did the previous two programs. Here, though, an asterisk (*) is used to tell SAS to determine the dimension of the qxs array, and the LBOUND and HBOUND functions are used to tell SAS to determine, respectively, the lower and upper bounds of the DO loop's index variable dynamically:
DATA survey3 (DROP = i);
INPUT subj q1 q2 q3 q4 q5 q6;
ARRAY qxs(*) q3-q6;
DO i = lbound(qxs) to hbound(qxs);
qxs(i) = qxs(i) - 1;
END;
DATALINES;
1001 1 2 1 2 1 1
1002 2 1 2 2 2 1
1003 2 2 2 1 . 2
1004 1 . 1 1 1 2
1005 2 1 2 2 2 1
;
RUN;
PROC PRINT data = survey3;
TITLE 'The survey data by changing upper and lower bounds automatically';
RUN;
Obs | subj | q1 | q2 | q3 | q4 | q5 | q6 |
---|---|---|---|---|---|---|---|
1 | 1001 | 1 | 2 | 0 | 1 | 0 | 0 |
2 | 1002 | 2 | 1 | 1 | 1 | 1 | 0 |
3 | 1003 | 2 | 2 | 1 | 0 | . | 1 |
4 | 1004 | 1 | . | 0 | 0 | 0 | 1 |
5 | 1005 | 2 | 1 | 1 | 1 | 1 | 0 |
If you compare this program with the previous program, you'll see that only two things differ. The first difference is that the asterisk (*) that appears in the ARRAY statement tells SAS to determine the bounds on the dimensions of the array during the declaration of qxs. SAS counts the number of elements in the array and determines that the dimension of qxs is 4. The second difference is that, for the DO loop, the bounds on the index variable i are determined dynamically to be between LBOUND(qxs) and HBOUND(qxs).
Now, launch and run the SAS program. Then, review the output from the PRINT procedure to convince yourself that the program does indeed recode the four variables q3, q4, q5, and q6 just as in the previous two programs.