DATA Step, Macro, Functions and more

Skip Macro iteration based on a file of no_run condition

Accepted Solution Solved
Reply
Super Contributor
Posts: 503
Accepted Solution

Skip Macro iteration based on a file of no_run condition

[ Edited ]

Hi Everyone,

 

I try to optimize my Macro program and here is my situation.

 

I have 2 DO-LOOP (DO a, DO h).

And I have a file contains all no checking condition (no_run file).

 

So at the beginning of the inner loop (DO h), I want to check if that “h” belong to the No-Checking condition or not. If belong, move to next iteration.

 

In the example, I dont want to run the main code for Height = 56 57 58 60.

(Clearly, for the simple problem below, I can simply delete the condition from the list of h)

 


*Create a No_run file to save value;
data no_run;
input height_no_run_value;
datalines;
56
57
58
60
;run;


%Macro skip;
	%let age_list	 = 12 13 ;
	%let Height_list = 50 51 53 55 56 57 58 60;

	%do a=1 	%to %sysfunc(countw(&age_list));
	%do H=1 	%to %sysfunc(countw(&Height_list));

		%put &h;


		/*Check the no-run value*/
			%if %scan(&height_list, &h) belong to no_run file %then %GOTO EXIT_STEP;


		/*MAIN CODE*/
		data Age&a._Height&H ; set have;
		if age=%scan(&age_list, &a) and height<%scan(&height_list, &h);run;

	%end;
	%EXIT_STEP:
	%end;
%Mend;

%SKIP;

 

KEY


data have; set sashelp.class; run;

*Create a No_run file to save value;
data no_run;
input height_no_run_value;
datalines;
56
57
58
60
;run;

proc sql;
select distinct height_no_run_value into : skip_list separated by ' ' from no_run;
quit;

%put &skip_list;run;


%Macro skip;
	%let age_list	 = 12 13 ;
	%let Height_list = 50 51 53 55 			56 57 58 59 60;

	%do a=1 	%to %sysfunc(countw(&age_list));
	%do H=1 	%to %sysfunc(countw(&Height_list));

		%put %scan(&height_list, &h);


		/*Check the no-run value*/

			%let one_age = %scan(&height_list, &h);

			%if %index(%str( &skip_list ), %str( &one_age )) = 0 %then %do;


		/*MAIN CODE*/
		data Age%scan(&age_list, &a)_Height%scan(&height_list, &h) ; set have;
		if age=%scan(&age_list, &a) and height<%scan(&height_list, &h);run;

		%end;

	%end;
	%EXIT_STEP:
	%end;
%Mend;

%SKIP;

Accepted Solutions
Solution
‎02-13-2018 10:13 AM
Super User
Posts: 6,541

Re: Skip Macro iteration based on a file of no_run condition

[ Edited ]

First, before calling the macro convert the list of values to skip to a single macro variable:

 

proc sql;

select distinct height_no_run_value into : skip_list separated by ' ' from no_run;

quit;

 

Then modify the macro definition to compare a single height value to the list of values in &SKIP_LIST.

 

As a general principle (and for this particular case as well), it would be a good idea to eliminate GOTOs.  That's easy enough to do here:

 

%Macro skip;
%let age_list = 12 13 ;
%let Height_list = 50 51 53 55 56 57 58 60;

%do a=1 %to %sysfunc(countw(&age_list));
%do H=1 %to %sysfunc(countw(&Height_list));

%put &h;

   /*Check the no-run value*/

   %if %index(&skip_list, %scan(&height_list, &h)) = 0 %then %do;

      /*MAIN CODE*/
      data Age&a._Height&H ; set have;
      if age=%scan(&age_list, &a) and height<%scan(&height_list, &h);run;


%end;

%end;
%end;


%Mend;

The %INDEX functions returns 0 when the second string does not appear within the first string.

 

If you had extreme values within &HEIGHT_LIST, additional care would have to be taken.  For example, "5" does actually appear within "57" and the %INDEX function would not return 0 under those conditions.  However, it seems likely that all your heights will be two digits long, and this complication will not be an issue.

View solution in original post


All Replies
Solution
‎02-13-2018 10:13 AM
Super User
Posts: 6,541

Re: Skip Macro iteration based on a file of no_run condition

[ Edited ]

First, before calling the macro convert the list of values to skip to a single macro variable:

 

proc sql;

select distinct height_no_run_value into : skip_list separated by ' ' from no_run;

quit;

 

Then modify the macro definition to compare a single height value to the list of values in &SKIP_LIST.

 

As a general principle (and for this particular case as well), it would be a good idea to eliminate GOTOs.  That's easy enough to do here:

 

%Macro skip;
%let age_list = 12 13 ;
%let Height_list = 50 51 53 55 56 57 58 60;

%do a=1 %to %sysfunc(countw(&age_list));
%do H=1 %to %sysfunc(countw(&Height_list));

%put &h;

   /*Check the no-run value*/

   %if %index(&skip_list, %scan(&height_list, &h)) = 0 %then %do;

      /*MAIN CODE*/
      data Age&a._Height&H ; set have;
      if age=%scan(&age_list, &a) and height<%scan(&height_list, &h);run;


%end;

%end;
%end;


%Mend;

The %INDEX functions returns 0 when the second string does not appear within the first string.

 

If you had extreme values within &HEIGHT_LIST, additional care would have to be taken.  For example, "5" does actually appear within "57" and the %INDEX function would not return 0 under those conditions.  However, it seems likely that all your heights will be two digits long, and this complication will not be an issue.

Super Contributor
Posts: 503

Re: Skip Macro iteration based on a file of no_run condition

Posted in reply to Astounding

Thanks a lot.

Turn into a string and index it is very interesting.

 

In my actual works, I do have the "extreme" value since the list run from 0-100.

 

Can you suggest me that additional treatment?

 

HHCFX

Frequent Contributor
Posts: 109

Re: Skip Macro iteration based on a file of no_run condition

%Macro skip;
	%let age_list	 = 12 13 ;
	%let Height_list = 50 51 53 55 56 57 58 60;

	%do a=1 	%to %sysfunc(countw(&age_list));
	%do H=1 	%to %sysfunc(countw(&Height_list));

		%put &h;


		/*Check the no-run value*/
		%let x=;
		data _null_;
		x=findw(&skip_list,%scan(&height_list, &h));
		call symput('x',x);
		run;
		%if &x. = 0 %then %do;

			/*MAIN CODE*/
			data Age&a._Height&H ; set have;
			if age=%scan(&age_list, &a) and height<%scan(&height_list, &h);run;
		%end;

	%end;
	%end;
%Mend;

%SKIP;

A few modifications to @Astounding code.
Hope this helps.

Super User
Posts: 6,541

Re: Skip Macro iteration based on a file of no_run condition

With extreme values, one way is to pad both %INDEX strings with blanks.  Before vs. after:

 

%if %index(&skip_list, %scan(&height_list, &h)) = 0 %then %do;

 

%if %index(%str( &skip_list ), %str( %scan(&height_list, &h) )) = 0 %then %do;

Super Contributor
Posts: 503

Re: Skip Macro iteration based on a file of no_run condition

Posted in reply to Astounding

Hi,

In your code, the error show up

ERROR: Macro function %SCAN has too few arguments.

 

In Satish_Parida, the error notice is:

388: LINE and COLUMN cannot be determined.
NOTE: NOSPOOL is on. Rerunning with OPTION SPOOL might allow recovery of the LINE and COLUMN
where the error has occurred.
ERROR 388-185: Expecting an arithmetic operator.
200: LINE and COLUMN cannot be determined.
NOTE: NOSPOOL is on. Rerunning with OPTION SPOOL might allow recovery of the LINE and COLUMN
where the error has occurred.
ERROR 200-322: The symbol is not recognized and will be ignored.

 

Even when I separate it, still that error.

		%let x=1;
		%let h=2;
		data _null_;
		height_list="1 2 3 4 5 6 7";
		skip_list="6 5 8";

		x=findw(&skip_list,%scan(height_list, &h));
		call symput('x',x);
		run;
Super User
Posts: 6,541

Re: Skip Macro iteration based on a file of no_run condition

OK, let's split it out as two statements, then.

 

Now:

 

%if %index(%str( &skip_list ), %str( %scan(&height_list, &h) )) = 0 %then %do;

 

The replacement (be sure to keep all those blanks inside the %INDEX function):

 

%let one_age = %scan(&height_list, &h);

%if %index(%str( &skip_list ), %str( &one_age )) = 0 %then %do;

Super Contributor
Posts: 503

Re: Skip Macro iteration based on a file of no_run condition

Posted in reply to Astounding

Oh, it works perfectly now.

By the way, why %GOTO is not prefered in Macro. I see it quite easy to control the flow of code.

Thank you so much.

HHCFX

Super User
Posts: 6,541

Re: Skip Macro iteration based on a file of no_run condition

Most programmers frown upon use of GOTO unless absolutely necessary.  As a general rule (and you could certainly argue that this particular case does not conform to the general rule), GOTO makes it difficult to follow the progression of the program as it moves through various processing steps.  It's easier to follow a program that moves from top to bottom, without the possibility of having to return to a prior step.

 

That being said, programming style is up to you.  It's really a question of what you find easy to read.

Super Contributor
Posts: 503

Re: Skip Macro iteration based on a file of no_run condition

Posted in reply to Astounding

Thanks for the tips.

I think if the code is team-based, GOTO will drive people crazy, but it is ok if you are the only one who write and run code.

HHC

☑ This topic is solved.

Need further help from the community? Please ask a new question.

Discussion stats
  • 9 replies
  • 183 views
  • 3 likes
  • 3 in conversation