BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
atulsingh
Obsidian | Level 7

Hello guys,

 

I am writing the below macro code to increase the number of cyl, such that the cars having hp > 150, cyl starts increasing till the time it gets equal to 10. Also, i have to reflect the magnitude by which the cyl has increased. 

Problem: In each of the cyl value, 10 is getting added.

 

%macro do_loop (var1,var2);
%if &var1 > 150 %then
%do i=1%to 10%by 1;
&var2=&var2+1;
%if &var2=10 %then leave;%end;;
%mend do_loop;

 

data macro_iterloop;
set loopcars;
%do_loop(hp,cyl);
proc print data=macro_iterloop;run;

 

The dataset is attached for reference. Please help

1 ACCEPTED SOLUTION

Accepted Solutions
RW9
Diamond | Level 26 RW9
Diamond | Level 26

Without examples how can I tell?  First write code which actually runs on one dataset, then look at how to change this to run on multiple datasets.  A quick change to my code:

%macro A (ds=,var=,oth=);
data want; set &ds.; &var.=ifn($oth. > 150,&var.=&var.+(10-&var.),&var.); run;
%mend A;
%A (ds=loopds,var=cyl,oth=hp);

And it becomes a macro.  But I started with Base SAS - which is the programming language - then I looked to see how it would be repeated, not the other way of writing macro code to try to force things.

View solution in original post

11 REPLIES 11
RW9
Diamond | Level 26 RW9
Diamond | Level 26

2 things, as mentioned before:

- Post test data in the form of a datastep in the post using the {i} code window.

- Macro is not needed.  From what I cans see here you doing a simple addition, so:

data want;
  set loopcars;
  cyl=ifn(hp > 150,cyl=cyl+(10-cyl),cyl);
run;

So if the condition is true, set cycl to add 10 up to 10, otherwise leave as is.  That is all thats needed (although I can't test as I will not download files and you haven't shown required output.

Also, make the Subject line a bit moore descriptive.

atulsingh
Obsidian | Level 7

I want the code to be wriiten in macros 

as i have different sets of observations with same varibale and same task is to be done for all of them.

RW9
Diamond | Level 26 RW9
Diamond | Level 26

Without examples how can I tell?  First write code which actually runs on one dataset, then look at how to change this to run on multiple datasets.  A quick change to my code:

%macro A (ds=,var=,oth=);
data want; set &ds.; &var.=ifn($oth. > 150,&var.=&var.+(10-&var.),&var.); run;
%mend A;
%A (ds=loopds,var=cyl,oth=hp);

And it becomes a macro.  But I started with Base SAS - which is the programming language - then I looked to see how it would be repeated, not the other way of writing macro code to try to force things.

Kurt_Bremser
Super User

@atulsingh wrote:

I want the code to be wriiten in macros 

as i have different sets of observations with same varibale and same task is to be done for all of them.


First of all, you DO NOT write "code" in macros. But you can make code dynamic for easier writing:

%macro set_max(var1,var2);
if &var1 > 150 then &var2 = max(&var2,10);
%mend;

data want;
set have;
%set_max(hp,cyl)
run;

Note that no macro code is inside the macro, just data step code with dynamic variable names.

Kurt_Bremser
Super User

Total misunderstanding of the macro preprocessor. The macro preprocessor is for creating dynamic code, NOT for handling data!

And there is a MUCH simpler solution than tediously counting up to a value:

data want;
set have;
if hp > 150 then cyl = max(cyl,10);
run;

 

 

Tom
Super User Tom
Super User

You can turn on MPRINT and MLOGIC to see what is happening.  Take a look at your macro, let's reformat it so that the macro logic steps are indented, but the SAS statements that it is generating are not.  

%macro do_loop (var1,var2);
  %if &var1 > 150 %then %do i=1 %to 10 %by 1;
&var2=&var2+1;
    %if &var2=10 %then leave;
  %end; 
; 
%mend do_loop;

So now let's look at the call  

%do_loop(hp,cyl)

And step through the macro logic and see what we expect it to do.  So if &VAR1 is replaced the hp and &VAR2 is replaced with cyl we get this body of the macro. 

  %if hp> 150 %then %do i=1 %to 10 %by 1;
cyl=cyl+1;
    %if cyl=10 %then leave;
  %end;
;

So let's check the logic. So the string "hp" is always greater than the string "150" so the %DO loop will run. And the string "cyl" is never equal to the string "10" so it never leaves early.  

 

So the macro will generate 10 assignment statements and one extra null statement.

 

As to your stated requirement:

 increase the number of cyl, such that the cars having hp > 150, cyl starts increasing till the time it gets equal to 10. Also, i have to reflect the magnitude by which the cyl has increased

 

To find the number of cylinders to add you will need some subtraction. To test value of HP you will need an IF statement. 

if hp > 150 and cyl > 10 then added_cyl = 10-cyl;
else added_cyl=0;
cyl=cyl+added_cyl;

Not sure how you could change this into a macro. What is it that varies?  Your example assumed it was the variable names, but to me it makes more sense that the values 150 and 10 would be the values that vary.

%macro add_cyl(hp_cutoff,max_cyl);
if hp > &hp_cutoff and cyl > &max_cyl then added_cyl = &max_cyl-cyl;
else added_cyl=0;
cyl=cyl+added_cyl;
%mend add_cyl;

 

 

atulsingh
Obsidian | Level 7
how the hp string will always be greater than 150. I think it will check first whether it's greater than 150 or smaller
Tom
Super User Tom
Super User

@atulsingh wrote:
how the hp string will always be greater than 150. I think it will check first whether it's greater than 150 or smaller

In the macro statement 

%if hp > 150 %then ...

The letters hp are just that, the letters hp.  They have nothing to do with any dataset variable that might be named using the same string of letters.

 

A lowercase H is always greater than the digit 1 in the ASCII coding system that SAS uses to store characters so hp is always greater than 150 in the lexigraphical ordering that SAS uses to compare strings.

 

 

atulsingh
Obsidian | Level 7

So how to refer hp to the 'hp variable in the csv dataset?

Tom
Super User Tom
Super User

@atulsingh wrote:

So how to refer hp to the 'hp variable in the csv dataset?


Use normal SAS statements like:

data ... ;
  set ... .;
if hp > 150 then ...

The SAS macro processor is for generating SAS code.

Kurt_Bremser
Super User

atulsingh wrote:
how the hp string will always be greater than 150. I think it will check first whether it's greater than 150 or smaller


You still suffer from a misunderstanding of what the macro processor is, what it does and when it does it.

The macro processor is invoked when a macro trigger (% or &) is encountered in the code while the code is read. It then produces text which is fed back to the "main" SAS interpreter for interpretation (or compilation in case of a data step). Since it does its work long before a data step runs, it has never access to the values present in the step.

Another feature of the macro processor is that it deals only with text; it has no datatype numeric. Your condition, translated to data step code, is therefore equivalent to

if "hp" > "150"

which is always true.

 

 

sas-innovate-2024.png

Don't miss out on SAS Innovate - Register now for the FREE Livestream!

Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.

 

Register now!

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
  • 11 replies
  • 1809 views
  • 2 likes
  • 4 in conversation