1

Within proc IML of the SAS system from within a user-defined module I want to be able to access the data in a vector by taking as an argument the name of the vector.

For example in the code below the module called "test" builds the two strings "x_vec1" and "x_vec2" but does not print the contents of these two vectors, but rather prints their names (I think submit blocks produce the same results).

This concept is very easily accomplished using macros by calling IML within macros, but I want to do it purely in IML to keep the code "clean". Whilst IML is brilliant for statistical work I need more than this - I need to keep my code short by having an analogous concept as the macro variable which can be resolved within a function at run time.

proc iml;

start test(ep);

  str = concat("x_",ep);
  print str;

finish;


x_vec1 = J(10,1,34);
x_vec2 = J(10,1,67);

run test("vec1");
run test("vec2");


quit;
Joe
  • 62,789
  • 6
  • 49
  • 67
dandar
  • 175
  • 1
  • 9

2 Answers2

3

The short answer to your question is that you need the function value.

proc iml;
 x_vec1 = J(10,1,34);
 str = cats('x_','vec1');
 _temp = value(str);
 print(_temp);
quit;

However, it doesn't work in a subroutine quite like you programmed it. That's because the subroutine needs to know that it's allowed to access the variable x_vec1 as a global variable - which you can't actually do here since you're specifying it on the fly.

You can get around this by PUSHing the command back to the calling environment, however.

start test(ep);
  str = cats('print(x_',ep,')');
  print(str);
  call push(str);
finish;

Not sure if this gives you the flexibility you need; if you are trying to do something more complex you may want to clarify what the final result needs to be.

Joe
  • 62,789
  • 6
  • 49
  • 67
  • Many thanks for this answer Joe - I never thought to use the push command. I don't really understand why this works, but I am happy it does! I think this apporach does give me the flexibility I need, although I will use the queue command instead to keep the ordering correct. Please see my code below; – dandar Oct 03 '14 at 16:29
  • This is similar to a regular SAS datastep, where you use `CALL EXECUTE` to execute code in a string: the code is given to the interpreter and called after the sub/datastep completes. What's important here is that the *sub* isn't actually executing the code for you; it's writing the code, and asking the calling environment to execute it for you. This is not that dissimilar to the macro language, of course. – Joe Oct 03 '14 at 16:37
  • Thanks for the brilliant explanation Joe, and yes this seems to be the macro language functionality I require but without using macros. – dandar Oct 03 '14 at 16:41
1

Using Joe's answer above, this new example accesses 2 vectors called "x_vec1" and "x_vec2" and adds a user defined amount to each element. Thus I think this approach can be used to create re-usable code that takes vector/matrix names as arguments.

proc iml;

start test(ep,n);

str1 = cats('print(x_',ep,');');
print str1;

str2 = cats('y_',ep,'= x_',ep,'+',char(n),';');
print str2;

str3 = cats('print(y_',ep,');');
print str3;

call queue(str1,str2,str3);

finish;


x_vec1 = J(10,1,34);
x_vec2 = J(10,1,67);

run test("vec1",10);
run test("vec2",100);


quit;
dandar
  • 175
  • 1
  • 9
  • Ok thanks Joe for the advice (if I am allowed to say thanks for being told not to say thanks). – dandar Oct 03 '14 at 17:24