Hello,
I would like to know whether it is possible to call marco variables with a looping code. Please see example below:
when i=1, I would like to get: _inval{1}=put( _invars{1},&_width1).
Current codes won't work.
data df1; a = .; b=1; c=1; output; a = 1; b=.; c=1; output; a = 1; b=1; c=.; output; run; %let _width1=3.1; %let _width2=3.2; %let _width3=3.3; data want ; set df1; array _invars{3} a b c; array _inval{3} $16 ; do i=1 to 3.; _inval{i}=put( _invars{i},&_widthi) ; /*I want to use &_width(i) where i change with i in looping setting */ end; run ;
I'd say, with OP setup there is no need for macro variables.
The PUTN which @PeterClemmensen mentioned is all is needed:
data df1;
a = .; b=1.235; c=1.234; output;
a = 1.234; b=.; c=1.234; output;
a = 1.234; b=1.234; c=.; output;
run;
data want ;
set df1;
array _invars{3} a b c;
array _inval{3} $16 ;
do i = 1 to 3;
_inval{i}=putn(_invars{i}, cats("5.",i)); /* build "5.i" text */
end;
put _all_;
run;
Bart
This is a classic SAS macro issue of timing. There are two main things you need to change in your code.
I changed the input values a bit, to make the result clearer. Feel free to ask.
data df1;
a = .; b=1.235; c=1.234; output;
a = 1.234; b=.; c=1.234; output;
a = 1.234; b=1.234; c=.; output;
run;
%let _width1=5.1;
%let _width2=5.2;
%let _width3=5.3;
data want ;
set df1;
array _invars{3} a b c;
array _inval{3} $16 ;
do i = 1 to 3;
f = symget(cats('_width', i));
_inval{i}=putn(_invars{i}, f);
end;
run;
Result:
a b c _inval1 _inval2 _inval3 i f . 1.235 1.234 . 1.24 1.234 4 5.3 1.234 . 1.234 1.2 . 1.234 4 5.3 1.234 1.234 . 1.2 1.23 . 4 5.3
I'd say, with OP setup there is no need for macro variables.
The PUTN which @PeterClemmensen mentioned is all is needed:
data df1;
a = .; b=1.235; c=1.234; output;
a = 1.234; b=.; c=1.234; output;
a = 1.234; b=1.234; c=.; output;
run;
data want ;
set df1;
array _invars{3} a b c;
array _inval{3} $16 ;
do i = 1 to 3;
_inval{i}=putn(_invars{i}, cats("5.",i)); /* build "5.i" text */
end;
put _all_;
run;
Bart
@PeterClemmensen Thanks so much!👍Can we do
putn(_invars{i}, &_width1.)
directly? I got error message for "expecting a format" 😅
One question might be very silly. How can I tell when an 'i' will change base on the looping i setup? I was hoping the i in &widthi will change when I do looping. Could you guide me on this? Thanks.
You have an error because PUTN() function (go to see its documentation: https://documentation.sas.com/doc/en/pgmsascdc/9.4_3.5/lefunctionsref/p12zqzvwx4dv6kn1p9crijxswolk.h... , unfortunatell the description there in vague)
expects a string constant or a character variable/expression which provides format name.
For example if
%let _width1=best32.20;
then your code should be:
/* option 1 */
putn(_invars{i}, "&_width1.")
/* option 2 */
putn(_invars{i}, symget("_width1"))
Basically, think about it that you want to have:
putn(variable, "format-name.")
/* or */
xxx="format-name.";
putn(variable, xxx)
Bart
@stataq wrote:
@PeterClemmensen Thanks so much!👍Can we do
putn(_invars{i}, &_width1.)
directly? I got error message for "expecting a format" 😅
One question might be very silly. How can I tell when an 'i' will change base on the looping i setup? I was hoping the i in &widthi will change when I do looping. Could you guide me on this? Thanks.
Remember that the macro processor is a PRE processor. The results after the macro processor has finished needs to be valid SAS code.
So what value did _WIDTH1 have? If it was just 5.3 (without any quotes) then your statement becomes something like:
putn(x,5.3)
Which is not valid SAS code because the PUTN() function wants a character value for the second argument (and a numeric value for the first. If you are formatting a character string use the PUTC() function instead.). In this context the string 5.3 is a number, not a character string. It might be interpreted as a format specification in locations where such was expected, but that is not what PUTN() expects.
So either add the quotes when referencing the macro variable:
putn(x,"&_width1")
Or make sure the quotes are in the macro variable.
%let _width1="5.3";
So that the resolved SAS code is something like:
putn(x,"5.3")
No need for macro variables. Just put the formats into another array.
data want ;
set df1;
array _invars a b c;
array _inval[3] $16 ;
array _formats[3] $8 _temporary_ ('5.1' '5.2' '5.3');
do i=1 to 3.;
/*I want to use &_width(i) where i change with i in looping setting */
_inval[i]=putN( _invars[i],_formats[i]);
end;
run ;
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
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.