问题
Hi I am trying to write a macro function with do loop and if statement. I think I have messed up the if-then do and do loop and I can't figure out the problem. I have a table of kids information, which contains columns like age, gender, sports, instruments etc,.
My original code, which works, looks like this:
data old;
set new;
if sports in ("football","basketball") and age <=7 then type =1;
else if sports='swimming' then type=2;
if special_kid=. then do;
if piano ^=. and piano_1 ^=. then do; talent_type=1; type_name=piano_1; end;
if violin ^=. and violin_1 ^=. then do; talent_type=1; type_name=violin_1; end;
end;
run;
I have a bunch of instruments that I want to edit the type and name. I want to write a loop to automatically do it, but I am not sure why the codes below doesn't work.
%let instrm = piano violin;
%macro my_func;
data old;
set new;
%if sports in ("football","basketball") and age <=7 %then type =1;
%else %if sports='swimming' %then type=2;
%do %while (special_kid=.);
%do i % to sysfunc(countw(&instrm));
%let word = %scan(&name, &i);
%if &word ^=. and ^word._1 ^=. %then %do;
talent_type=1; type_name=&word._1;
%end;
%end;
%end;
run;
%mend;
It keeps giving me the errors
ERROR: An unexpected semicolon occurred in the %DO statement.
ERROR: A dummy macro will be compiled.
Can anyone please answer my question? Thanks!
回答1:
The macro variable instrm
is really a value containing a space separated list of variable names. You might be better off abstracting away from the specific variable use role and fallback to a more generic parameter name vars
. Also, rather than relying on a macro variable defined in a global or encompassing scope, pass the list in during invocation. You are correct that a space separated list can be iterated over in macro with a %do
loop with a top limit that is the countw
number of 'words' in the list--your syntax is only a little off.
You don't have to macro-ize everything, and the extra macroification of the sports logic went to far. Remember, macro invocations emit (or generates) source code that feeds into the SAS submit system. The macro coding coding process when more abstract or toolboxy is sometimes referred to as codegen.
Your original code may be faulty because you evaluate (in a single row) multiple special kid variables and perform value assignments to the same 2 variables (talent_type
and type_name
) and thus may overwrite a value previously assigned. Sometimes, such evaluations and assignments are OUTPUT
to separate rows.
%macro my_skill_classifier(data=, out=, special_vars=, special_type=);
%local i var;
data &out;
set &data;
if sports in ("football","basketball") and age <=7 then type = 1;
else
if sports='swimming' then type=2;
* what happens to football/baskeball > 7yr ?;
if missing(special_kid) then do;
%do i = 1 %to sysfunc(countw(&special_vars));
%let var = %scan(&special_vars, &i);
* regular data step code with macro resolutions sprinkled in;
if &var ^=. and var._1 ^=. then do;
talent_type = &special_type;
type_name = &var._1;
* maybe you really mean type_name = "&var._1";
end;
%end; %* end loop over special_vars list;
end;
run;
%mend;
%my_skill_classifier(data=new, out=old, special_vars=piano violin, special_type=1)
In long, make sure your data shaping and evaluation processing methodology is rock solid before starting your macro coding. If you ask yourself Should I macro this?, be conservative and answer no. Be friendly to maintainers and future-self by not over complicating things.
回答2:
There were few tweaks required in your code, I did some changes. Also, when we are using %if we always use macro variables. Otherwise we are good to use just if statements with normal dataset variables.
%let instrm = piano violin;
%macro my_func;
data old;
set new;
if sports in ("football","basketball") and age <=7 then type =1;
else if sports='swimming' then type=2;
if missing(special_kid) then do;
%do i=1 %to %sysfunc(countw(&instrm));
%let word = %scan(&instrm, &i);
%If &word ^=. and &word._1 ^=. %then %do;
talent_type=1; type_name=&word._1;
%end;
%end;
end;
run;
%mend my_func;
来源:https://stackoverflow.com/questions/53179237/sas-if-statement-in-do-loop