BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
stataq
Quartz | Level 8

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 ;
1 ACCEPTED SOLUTION

Accepted Solutions
yabwon
Onyx | Level 15

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

_______________
Polish SAS Users Group: www.polsug.com and communities.sas.com/polsug

"SAS Packages: the way to share" at SGF2020 Proceedings (the latest version), GitHub Repository, and YouTube Video.
Hands-on-Workshop: "Share your code with SAS Packages"
"My First SAS Package: A How-To" at SGF2021 Proceedings

SAS Ballot Ideas: one: SPF in SAS, two, and three
SAS Documentation



View solution in original post

6 REPLIES 6
PeterClemmensen
Tourmaline | Level 20

This is a classic SAS macro issue of timing. There are two main things you need to change in your code.

 

  1. Use the PUTN Function instead of the PUT Function. The PUTN Function enables you to specify a numeric format at run time. The Put Function does so at compile time, i.e. before the loop executes. 
  2. Use the Symget Function in the Data Step to retrieve the value of the macro variable during DATA step execution (not when it compiles).

 

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

 

yabwon
Onyx | Level 15

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

_______________
Polish SAS Users Group: www.polsug.com and communities.sas.com/polsug

"SAS Packages: the way to share" at SGF2020 Proceedings (the latest version), GitHub Repository, and YouTube Video.
Hands-on-Workshop: "Share your code with SAS Packages"
"My First SAS Package: A How-To" at SGF2021 Proceedings

SAS Ballot Ideas: one: SPF in SAS, two, and three
SAS Documentation



stataq
Quartz | Level 8

@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.

yabwon
Onyx | Level 15

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

_______________
Polish SAS Users Group: www.polsug.com and communities.sas.com/polsug

"SAS Packages: the way to share" at SGF2020 Proceedings (the latest version), GitHub Repository, and YouTube Video.
Hands-on-Workshop: "Share your code with SAS Packages"
"My First SAS Package: A How-To" at SGF2021 Proceedings

SAS Ballot Ideas: one: SPF in SAS, two, and three
SAS Documentation



Tom
Super User Tom
Super User

@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")

 

Tom
Super User Tom
Super User

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 ;

SAS Innovate 2025: Call for Content

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!

Submit your idea!

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 6 replies
  • 371 views
  • 8 likes
  • 4 in conversation