I'm relatively new to macro functions. I'm trying to build a function that, when supplied with numeric parameter "N", will return the Nth word from a macro variable. I've been mostly successful, but for some reason the function I've created works when supplying a number, but not when supplying a numeric variable as argument.
Here's a paired down Macro list:
/*Please note these are generalized versions*/
%let MACRO_LIST = "A" "B" "C" "D" "E" "F" "G";
This is the exact function I'm using. It works when a number is supplied as argument, but does not work when that number is itself stored as a variable.
/*Return item at supplied position N from macro_list*/;
%macro Nth_ITEM(n);
%SCAN(%superq(MACRO_LIST), &n);
%mend Nth_ITEM;
Here's a simplified example of where the error occurs.
/*CODE PRODUCING THE ERROR:*/
data my_data;
do i = 1 to 10;
ID_no = i;
Identifier = %Nth_ITEM(i); /*raises*/
output;
end;
drop i;
run;
/* THE FOLLOWING ERRORS ARE THROWN:
ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was:
i
ERROR: Argument 2 to macro function %SCAN is not a number.
ERROR 22-322: Syntax error, expecting one of the following: a name, a quoted string, a numeric constant, a datetime constant,
a missing value, INPUT, PUT.
ERROR: The macro NTH_ITEM will stop executing.
*/
But directly supplying a number works
/*THIS WORKS??:*/
data my_data;
do i = 1 to 10;
ID_no = i;
Identifier = %Nth_ITEM(4); /*Sets Identifier = "D" for all 10 rows*/
output;
end;
drop i;
run;
Ideally, the resulting (extremely simplified) data would look like this:
ID_no | Identifier |
---|---|
1 | A |
2 | B |
.... | .... |
10 | G |
What am I doing wrong with the macro function call? Why does it work when a number is supplied, but not when a variable is supplied? Is there something I can change to make work the way I'd like it to, or is something fundamentally wrong with this approach?
Thank all
EDIT: Just realized I only included 7 letters, pretend there are 10 letters in MACRO_LIST
This is because the macro is run before the data step code is compiled. Think of macros as a very fancy form of copy/paste. SAS is going to compile or run any macros, then compile the data step code. i
does not yet exist as far as the macro is concerned. Constants will work since they are already initialized: it's a valid value that the macro can use.
You do not need to use a macro to do this. You can modify your macro list to be space-separated, then use scan()
. It's generally a good practice to not include quotes in your macro list when possible. You can resolve macros within double-quotes.
%let MACRO_LIST = A B C D E F G;
data my_data;
do i = 1 to 10;
ID_no = i;
Identifier = scan("¯o_list", i);
output;
end;
drop i;
run;
Before the data step code is compiled, ¯o_list
will resolve. SAS will see this in the data step:
Identifier = scan("A B C D E F G", i);