1

I want to use a macro do loop inside proc iml like so:

%Let Tab1=FirstTable;
%Let Tab2=SecondTable;
%Let Tab3=ThirdTable;

*&Tab1-3 have been initialised as sas datasets;   

proc iml;

* This works;

use &Tab1;
read all into Mat3;
print Mat3;


* This doesn't work;

%Macro Define_mx;
    %do i=1 %to 2;
    use &Tab&i;
    read all into Mat&i ;
   %end;
  %Mend Define_mx;
%Define_mx;

*The two matrixes have not been initialised;

print Mat1;
print Mat2;
quit;

In reality I will have to initialise like 50 matrixes so a do-loop is necessary. I can't figure out why the loop can't see &Tab&i as a macro variable. I also tried a workaround with a normal (non-macro) do-loop using substr to concatenate the variable names but it didn't work either. What am I missing here ?

Pane
  • 555
  • 2
  • 7
  • 20
  • Double amperstand on Tab... I'm an idiot. – Pane Jul 05 '13 at 18:35
  • 1
    Brilliant! Please submit your solution as an answer and accept it. This is definitely a sufficiently common mistake that it's worth having as a solution in StackOverflow :) – Joe Jul 05 '13 at 19:17

2 Answers2

2

Ok, so the macro should be:

%Macro Define_mx;
 %do i=1 %to 2;
   use &&Tab&i;
   read all into Mat&i ;
 %end;
 %Mend Define_mx;
%Define_mx;

The second amperstand on Tab is necessary as without it the macro processor would try to interpret &Tab as a macro variable (which does not exist). Thus, when trying to concatenate multiple macro variables to create a new one, use &&.

Pane
  • 555
  • 2
  • 7
  • 20
1

If you have SAS/IML 12.1 (released with 9.3m2), there is an even simpler way. The USE statement supports dereferencing data set names, like this:

ds = "MyData";
use (ds);

Furthermore, as I show in my article on using the VALSET function, the SAS/IML language supports the VALSET function, which can dynamically create matrices named Mat1, Mat2, and so on. You can combine these features to eliminate the macros entirely:

data a b c;                 /* create sample data sets */
x=1;y=2; output;
x=2;y=3; output;
run;

proc iml;
dsnames = {a b c};          /* names of data sets */
do i = 1 to ncol(dsnames);
   use (dsnames[i]);        /* open each data set */
   read all into X;
   close (dsname);
   MatName = "Mat"+strip(char(i)); /* create Mat1, Mat2,... */
   call valset(MatName, X);        /* assign values from data set */
end;
show names;
Rick
  • 1,210
  • 6
  • 11
  • Getting rid of the macro was my goal at some point also. I guess you could write `call valset("Mat"+strip(char(i)));` with your solution to make it more neat. Unfortunately, I'm still on 9.2. As I understand this solution won't work with this version ? – Pane Jul 08 '13 at 17:13