BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
weg
Obsidian | Level 7 weg
Obsidian | Level 7

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?

1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

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_; 

 

View solution in original post

6 REPLIES 6
Patrick
Opal | Level 21

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.

Reeza
Super User

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?


 

Tom
Super User Tom
Super User

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_; 

 

weg
Obsidian | Level 7 weg
Obsidian | Level 7

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;

 

Tom
Super User Tom
Super User
I don't get how you are telling the macro how large to make the array. Your posted code uses a fixed value of 5 for NDIM. What does that number mean in terms of the larger problem. Where is it defined? What happens if NDIM changes between calls? Do you want the DO loop to use DIM(arrayname) instead of &NDIM as the upper bound?
One risk is that forget to run the clean up step so that you never end up ever generating the array statement. Then the generated SAS code will fail.
Another is whether these separate calls actually WANT to use the same array or not. What if they want to use it for different things? And want to put different values into the variables in the array.
This whole series of questions in this vein you have asked about all really look like XY problems to me. http://xyproblem.info/
weg
Obsidian | Level 7 weg
Obsidian | Level 7

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: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

How to Concatenate Values

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 6 replies
  • 1218 views
  • 2 likes
  • 4 in conversation