I have a macro program that performs some calculations on an array and sticks them in another array. I don't want to declare the array if the macro has already been called, and just skip to changing the values.
if not( /* &arrayname exists /* ) then do; array &arrayname._calculations [&ndim] _TEMPORARY_; end;
Is there a function or some easy way to check this?
You cannot use DATA step code to conditionally generate an ARRAY statement. ARRAY statements only have an effect during the compilation of the data step. Your macro needs to know whether or not it has already generated that ARRAY statement for this data step. Or just have the macro generate a NEW array name each time it is called. For example by using the value of &SYSINDEX in the name.
array &arrayname._&sysindex._calc [&ndim] _TEMPORARY_;
Arrays get declared during compilation time and not execution time. The IF condition comes only into play during execution time. For this reason declaring an array conditionally on SAS data step level is not possible.
You will need to implement this on macro level meaning that your macro needs logic to only generate the SAS array statement the first time you call it.
You can use VARRAY() to check if a variable belongs to an array, but not if the array exists AFAIK.
Given your array declaration which doesn't use variable names it's a bit of a harder process.
@weg wrote:
I have a macro program that performs some calculations on an array and sticks them in another array. I don't want to declare the array if the macro has already been called, and just skip to changing the values.
if not( /* &arrayname exists /* ) then do; array &arrayname._calculations [&ndim] _TEMPORARY_; end;Is there a function or some easy way to check this?
You cannot use DATA step code to conditionally generate an ARRAY statement. ARRAY statements only have an effect during the compilation of the data step. Your macro needs to know whether or not it has already generated that ARRAY statement for this data step. Or just have the macro generate a NEW array name each time it is called. For example by using the value of &SYSINDEX in the name.
array &arrayname._&sysindex._calc [&ndim] _TEMPORARY_;
edit-- benchmarking the performance doesn't show a real different in speed than just creating new arrays each time, so that seems like the simplest and most foolproof solution.
So I made a new macro variable for each array input that counts how many times the macro function has been called and initalize based off of that, and then I need to run a macro at the end to clear all these "temp" macro variables from the symbol table. It seems to be working, other than the fact that if it crashes halfway through I have to manually run the cleanup code by itself before the program runs. I'm not sure if this is better or worse than just making separate arrays each time the function is called, but is there any obvious thing I could screw up by doing things this way?
%macro testmac(arrayname);
%let ndim = 5;
%if %symexist (_i_&arrayname) %then %let _i_&arrayname = %eval(&&_i_&arrayname+1);
%else
%do;
%global _i_&arrayname;
%let _i_&arrayname=1;
%end;
%if &&_i_&arrayname=1 %then
%do;
array &arrayname._calc[&ndim] ; /* its _temporary_ always, I just wanted to see output */
%end;
do i = 1 to &ndim;
&arrayname._calc[i] = 5;
end;
%mend;
%macro rmHDPmac;
options nonotes;
%local vars;
proc sql noprint;
select name into: vars separated by ' '
from dictionary.macros
where scope='GLOBAL'
and name contains '_i_';
quit;
data _null_;
call execute('%symdel &vars;');
run;
options notes;
%put NOTE: Macro variables deleted: &vars;
%mend rmHDPmac;
data test;
%testmac(arrayname=array1);
%testmac(arrayname=array1);
%testmac(arrayname=array1);
%testmac(arrayname=array2);
run;
%rmHDPmac;
Thanks for the help, I ended up using the SYSINDEX method as it didn't substantially increase the run time.
You are right that I have to calculate NDIMS, arrayvalues etc I have all of that tested and working fine, the only hitch was that last array generation part and it didn't seem that the ndims or actual values of the array would change the process of initializing the new arrays themselves which is the only thing I have trouble with. I definitely understand where you are coming from by giving the full problem and code, but I have to give a minimum working example because even if I was authorized to share a the input and output to the full macro it wont make sense anyway on its own, and it has to interface with code people have already written and can't change.
But the macros I've needed to make over the past week are complete and working as of now, and I am really grateful for the help.
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.