Desktop productivity for business analysts and programmers

passing variable to array

Reply
N/A
Posts: 0

passing variable to array

Hi. I have an array that varies in size which depends on another variable ("Var"). I am trying to define another array that is based on the size of this array by using the dim statement. But SAS is not happy with what I have done:

Array ArrayVar1{*} Var: ;
%Let j = dim (ArrayVar1) ;
Array ArrayVar2{&j} ;

Any ideas on how to make this work?
SAS Super FREQ
Posts: 8,820

Re: passing variable to array

Hi:
I'm not exactly sure what you're trying to do. Is this a code snippet from a SAS Macro program or a code snippet from a DATA step program? At any rate, the %LET statement is a COMPILE time statement. No data is read at compile time, so there is no possibility that you will have a value for &J at compile time. However, there is a way to figure out what the dimension of the new array should be. It just takes making your macro variable --outside-- of the data step where you need to use the macro variable. This is because if you create a macro variable inside a data step (with a CALL SYMPUT), you cannot USE it until after a step boundary has been encountered.

Here's an example. I know that there are 3 numeric variables in SASHELP.CLASS. I can do this with %LET:
[pre]

%let arrdim = 3; /* set at compile time */

data testarr;
set sashelp.class;
array c_num (*) _numeric_;
array wombat (&arrdim) ;
do i = 1 to dim(c_num);
wombat(i) = c_num(i);
end;
run;

proc print data=testarr;
run;
[/pre]

But note that the %LET statement is OUTSIDE of the DATA step with the reference to &ARRDIM. What you probably want to do, I -think- is have SAS determine what number to use for the array dim without hard-coding the value.

So, consider this data in WORK.MYCHARS:
[pre]
Obs show howmany char1 char2 char3 char4 char5 char6

1 I Love Lucy 4 Lucy Ricky Ethel Fred
2 Muppet Show 5 Kermit Gonzo Swedish Chef Miss Piggy Rowlf
3 Sesame Street 4 Big Bird Elmo Kermit Oscar
4 The Odd Couple 2 Oscar Felix

[/pre]

I have a SHOW variable and a count variable (HOWMANY) that tells me how many characters there are for each show. I also have CHAR1-CHAR6 in the data, but the show with the most characters only has 5 characters.

So, with this PROC SQL, I will find out the MAX number of characters and I will put the max number of characters into a macro variable called &CHARDIM. (I also could have calculated the HOWMANY variable when I read in the data and created the macro variable there, but you said you had a variable with the number.)
[pre]
proc sql noprint;
select max(howmany) into :chardim
from work.mychars;
quit;

%let chardim = &chardim;
%put ************************;
%put largest number of characters is &chardim;
%put use this value in next data step;
%put ************************;

[/pre]
Now, I have a value for &CHARDIM, and I can see it in the SAS Log after the SQL step runs:
[pre]
2145 %let chardim = &chardim;
2146 %put ************************;
************************
2147 %put largest number of characters is &chardim;
largest number of characters is 5
2148 %put use this value in next data step;
use this value in next data step
2149 %put ************************;
************************

[/pre]

Now, I want to run a program, where I use &CHARDIM to KEEP only CHAR1-CHAR5 and to make new variables NA1-NA5. Since &CHARDIM is now in the Global Symbol Table, I can use in in my program and it will be available when the program compiles (which I could prove by turning on the MPRINT and SYMBOLGEN options):
[pre]
options mprint symbolgen;
data usedim;
keep show howmany char1-char&chardim na1-na&chardim;
set mychars;
array c_arr $ char1-char&chardim;
array newarr {&chardim} $12 na1-na&chardim;
do i = 1 to dim(c_arr);
if c_arr(i) = 'Kermit' then
newarr(i) = 'Best';
else if c_arr(i) = 'Oscar' then
newarr(i) = 'Messiest';
else if c_arr(i) = "Lucy" then
newarr(i) = 'Funny';
else if c_arr(i) = "Miss Piggy" then
newarr(i) = "Loves Kermit";
else if i le howmany then newarr(i) = 'OK';
else newarr(i) = ' ';
end;
run;

options linesize=120;
proc print data=usedim;
title "Use chardim of &chardim to define the array and variables";
title2 "And only keep vars: show, howmany, char1-char&chardim and na1-na&chardim";
run;

[/pre]

But let's just take these 3 statements...I have this in the program:
[pre]
keep show howmany char1-char&chardim na1-na&chardim;
....
array c_arr $ char1-char&chardim;
array newarr {&chardim} $12 na1-na&chardim;
[/pre]

The above statements get sent to the Macro Processor for resolution BEFORE compile time...so when the macro processor is done with those 3 statements, THIS is what the compiler sees and compiles and are the statements that finally execute:
[pre]
keep show howmany char1-char5 na1-na5;
....
array c_arr $ char1-char5;
array newarr {5} $12 na1-na5;
[/pre]

Every place that the macro processor saw &CHARDIM, it "typed in" or substituted a "5" in the string that it was building for the compiler. Essentially, the macro processor used the value of &CHARDIM -- and the compiler only saw the resolved statements. So, the output from the proc print is:
[pre]
Use chardim of 5 to define the array and variables
And only keep vars: show, howmany, char1-char5 and na1-na5

Obs show howmany char1 char2 char3 char4 char5 na1 na2 na3 na4 na5

1 I Love Lucy 4 Lucy Ricky Ethel Fred Funny OK OK OK
2 Muppet Show 5 Kermit Gonzo Swedish Chef Miss Piggy Rowlf Best OK OK Loves Kermit OK
3 Sesame Street 4 Big Bird Elmo Kermit Oscar OK OK Best Messiest
4 The Odd Couple 2 Oscar Felix Messiest OK

[/pre]

There are a couple of different ways I could have coded the DO loop -- I could have coded DO i = 1 to howmany; -- which probably would have simplified my IF statements...but this is a place to start with what I -think- you're trying to do. Also remember that the ARRAY statement is only setting up a convenient reference for a group of related variables. The array "names" C_ARR or NEWARR are never saved in the SAS data set. In one program I could have the ARRAY named C_ARR, but in a different program, I could name the array KOALA and refer to the same variables that had been referenced as C_ARR(i) with KOALA(i):
[pre]
Program 1 has:
set work.mychars;
array KOALA $ char1-char6;

Program 2 has:
set work.mychars;
array C_ARR $ char1-char6;

[/pre]

In other words, SAS never keeps the ARRAY name. It only keeps the variables that were treated as an array for the duration of the program. For the above 2 programs, the arrays were both referring to the same variables. In some data base systems, ARRAYS are a physical data construct and information about the array is stored in the data base, but in SAS, the ARRAY information does not persist once the program is over....only the individual variable names persist.

cynthia
N/A
Posts: 0

Re: passing variable to array

Fantastic, thanks Cynthia
Sorry, I should have specified that this was in a data step, but you hit the nail on the head. Is there a way of determining the size of var_1-var_5/6/7 outside the data step?
SAS Super FREQ
Posts: 8,820

Re: passing variable to array

Hi:
SAS has an extensive group of "dictionary" tables or "sashelp" tables that contain information about the datasets. You can reference these files without opening the relevant dataset.

[pre]
title 'Dictionary.Columns info';
proc sql;
select name, length, type, format
from dictionary.columns
where libname="WORK" and
memname="MYCHARS";
run;

proc print data=sashelp.vcolumn noobs;
title 'SASHELP.VCOLUMN info';
where libname="WORK" and memname="MYCHARS";
var name length type format;
run;
[/pre]

There have been lots of user-group papers written on the topic of using SAS Dictionary tables and/or the SASHELP equivalent of the tables. A Google search should help you find some more examples of usage.

cynthia
Ask a Question
Discussion stats
  • 3 replies
  • 150 views
  • 0 likes
  • 2 in conversation