DATA Step, Macro, Functions and more

creating a usable macro variable in a do loop..

Reply
N/A
Posts: 0

creating a usable macro variable in a do loop..

I'm stumped.

In the example below i have created the variables B1, B2, B3, B4 and B5. They have the values 1,5,2,6 and 3 respectively.

I have also created the variables M1, M2, M3, M4 and M5, using an array, which I want to take the following values.

M1=B1;
M2=max(of B1-B2);
M3=max(of B1-B3) etc...

I need to do this within the do loop for various reasons which I won't go into now. Anyway, this code looks to me like it should work fine. But it doesn't. It looks like the Call Symput doesn't create the global variable &bobno until the datastep has finished running, I need the variable to be created during the do loop to ensure that the correct max(B1-B&bobno) is calculated to give the correct value in M1-M5.

Help?

Sample Code:



data play;

B1=1;
B2=5;
B3=2;
B4=6;
B5=3;

array maxi(5) M1-M5;

do i=1 to 5;
call symput ('bobno',compress('B'||i));
maxi(i)=max(of B1-&bobno);
end;

run; Amended as I pasted in the wrong code.


Message was edited by: cstanyer
Super Contributor
Super Contributor
Posts: 3,174

Re: creating a usable macro variable in a do loop..

Posted in reply to deleted_user
I get a SAS error when I execute your "sample" code. Best to share more about your actual SAS code and a SASLOG error problem excerpt.

Scott Barry
SBBWorks, Inc.
N/A
Posts: 0

Re: creating a usable macro variable in a do loop..

I too get an error, which is why I am here.

In theory, this do loop would work if the call symput assigned during the processing. It appears that it does not until the datastep is complete.

Using a %let doesn't work either as that doesn't resolve the compress function.
Super User
Posts: 5,431

Re: creating a usable macro variable in a do loop..

Posted in reply to deleted_user
No, call symput will not be executed until after the data step have finished, so there little you can do about changing the syntax within the data step itself.

Try this, does it suit your needs?

data play;

B1=1;
B2=5;
B3=2;
B4=6;
B5=3;
array b(5) b1-b5;
array maxi(5) M1-M5;

m1=b1;
do i=2 to 5;
maxi(i)=max(maxi(i-1),b(i));
end;

run;

/Linus
Data never sleeps
SAS Super FREQ
Posts: 8,868

Re: creating a usable macro variable in a do loop..

Posted in reply to deleted_user
Hi:
Just as you use CALL SYMPUT to write to the Global Symbol table from a "running" Data Step program, you generally use SYMGET to retrieve values from the Global Symbol table inside a "running" Data Step program.

The reference to &bobno, will only resolve 1 time -- at compile time. So whatever value you are seeing is either left over from the previous DATA step execution or, if there is no value for &bobno at the first compile, then you are probably getting a macro variable not found error.

I am a bit confused over WHY you are trying to generate this using macro variables. Is this really the code you envision:
[pre]
m1 = max(of B1-B1);
m2 = max(of B1-B2);
m3 = max(of B1-B3);
m4 = max(of B1-B4);
m5 = max(of B1-B5);
[/pre]

I think the statement for M1 will give you problems because B1-B1 is not a proper range of numbers for the OF usage. I just don't see how macro variables fit into the picture.

cynthia
N/A
Posts: 0

Re: creating a usable macro variable in a do loop..

Posted in reply to Cynthia_sas
Linus - that works great in this example - I'll try it in my main code.


Cynthia, in the sample I provided a very basic version of what I am trying to achieve. Basically there are a lot more variables in my working example e.g. M1-M90 and the number changes depending on when the code is run.

I have been asked to design all my code so that the users, who are not technical, can simply open and run without having to input any dates, or amend anything. I have managed to get everything else automated and just need to create the field M1-Mn where I have created n as a global variable based on date.

I think I have everything I need now thanks to these forums.
N/A
Posts: 0

Re: creating a usable macro variable in a do loop..

Posted in reply to deleted_user
I really was trying to overcomplicate everything wasn't I?

Thanks again.
SAS Super FREQ
Posts: 8,868

Re: creating a usable macro variable in a do loop..

Posted in reply to deleted_user
Great! Glad you have a solution that works for you.

I'd like to clarify something for future reference. CALL SYMPUT executes on every iteration of the DATA step program to CREATE a macro variable -- at execution time (or in your case, for every iteration of the DO loop). An "&macvar" reference only gets resolved at COMPILE time. That means if you use CALL SYMPUT and an &macvar reference, you have a timing issue because the &macvar will be resolved, if possible BEFORE the CALL SYMPUT executes.

Usually, you don't CREATE a macro variable and then REFERENCE that macro variable with an &macvar reference in the same program.
&bobno will not be available for compile time resolution until after the creating datastep is over, as described here:
http://support.sas.com/kb/23/182.html
http://support.sas.com/kb/22/987.html

--and when it IS available, it will ALWAYS be whatever value was the LAST value assigned in the CALL SYMPUT -- which in your case would always be B5.

The documentation on CALL SYMPUT and SYMGET are here. The SYMGET doc has a good example of using SYMGET from a previously SYMPUT-created variable:
http://support.sas.com/documentation/cdl/en/mcrolref/59526/HTML/default/a000210266.htm
http://support.sas.com/documentation/cdl/en/mcrolref/59526/HTML/default/a000210322.htm

This program shows an interesting use of CALL SYMPUT and SYMGET that proves the macro variable 'bobno' is getting set appropriately for every iteration of the DO loop -- it also proves that at the end of the do loop, 'bobno' is set to B5. Usually, when you have a DO loop and a CALL SYMPUT, you are creating numbered macro variables (also shown):
[pre]
421 data play;
422
423 do i=1 to 5;
424 call symput ('bobno',compress('B'||i));
425 val = symget('bobno');
426 call symput ('bobno'||put(i,1.0),compress('B'||i));
427 put _all_;
428
429 end;
430
431 run;

NOTE: Numeric values have been converted to character values at the places given by:
(Line)Smiley SadColumn).
424:41 426:53
i=1 val=B1 _ERROR_=0 _N_=1
i=2 val=B2 _ERROR_=0 _N_=1
i=3 val=B3 _ERROR_=0 _N_=1
i=4 val=B4 _ERROR_=0 _N_=1
i=5 val=B5 _ERROR_=0 _N_=1
NOTE: The data set WORK.PLAY has 1 observations and 2 variables.
NOTE: DATA statement used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds


432
433 %put after data step: bobno = &bobno;
after data step: bobno = B5
434 %put bobno1 = &bobno1;
bobno1 = B1
435 %put bobno2 = &bobno2;
bobno2 = B2
436 %put bobno3 = &bobno3;
bobno3 = B3
437 %put bobno4 = &bobno4;
bobno4 = B4
438 %put bobno5 = &bobno5;
bobno5 = B5

[/pre]

Note that when using SYMGET to create the variable VAL, VAL changes for every iteration of the DO loop; in a similar fashion VAL
would change on every iteration of a DATA step program. The usual way that macro variables are set in a DO loop are to use i as part of
the macro variable value (as shown). The FINAL value of bobno is B5...because at every iteration of the do loop, you are writing over the
previously set value.

cynthia
Ask a Question
Discussion stats
  • 7 replies
  • 239 views
  • 0 likes
  • 4 in conversation