do 循环中的 SAS if 语句
SAS if statement in do loop
您好,我正在尝试编写一个带有 do 循环和 if 语句的宏函数。我想我搞砸了 if-then do 和 do 循环,我无法找出问题所在。
我有一个 table 儿童信息,其中包含年龄、性别、运动、乐器等列。
我的原始代码是这样的:
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;
我有一堆乐器要编辑类型和名称。我想写一个循环来自动执行它,但我不确定为什么下面的代码不起作用。
%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;
它一直给我错误
ERROR: An unexpected semicolon occurred in the %DO statement.
ERROR: A dummy macro will be compiled.
有人可以回答我的问题吗?谢谢!
宏变量 instrm
实际上是一个包含 space 分隔的变量名列表的值。您最好从特定的变量使用角色中抽象出来,然后回退到更通用的参数名称 vars
。此外,与其依赖在全局或包含范围内定义的宏变量,不如在调用期间传入列表。您是正确的,space 分隔列表可以在宏中使用 %do
循环迭代,其上限是列表中 'words' 的 countw
数量——你的语法只是有点偏差。
你不必宏观化一切,体育逻辑的额外宏观化已经很远了。请记住,宏调用发出(或生成)输入 SAS 提交系统的源代码。宏编码编码过程比较抽象或者toolboxy有时也被称为codegen。
您的原始代码可能有错误,因为您评估(在一行中)多个特殊的 kid 变量并对相同的 2 个变量(talent_type
和 type_name
)执行赋值,因此可能会覆盖先前分配的值。有时,这样的评估和分配是 OUTPUT
分隔行。
%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)
总而言之,在开始宏编码之前,请确保您的数据整形和评估处理方法是坚如磐石的。如果您问自己 我应该对此进行宏设置吗?,请保守一点并回答否。对维护者和未来的自己友好,不要让事情过于复杂。
您的代码几乎不需要调整,我做了一些更改。此外,当我们使用 %if 时,我们总是使用宏变量。否则我们最好只使用带有普通数据集变量的 if 语句。
%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;
您好,我正在尝试编写一个带有 do 循环和 if 语句的宏函数。我想我搞砸了 if-then do 和 do 循环,我无法找出问题所在。 我有一个 table 儿童信息,其中包含年龄、性别、运动、乐器等列。
我的原始代码是这样的:
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;
我有一堆乐器要编辑类型和名称。我想写一个循环来自动执行它,但我不确定为什么下面的代码不起作用。
%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;
它一直给我错误
ERROR: An unexpected semicolon occurred in the %DO statement.
ERROR: A dummy macro will be compiled.
有人可以回答我的问题吗?谢谢!
宏变量 instrm
实际上是一个包含 space 分隔的变量名列表的值。您最好从特定的变量使用角色中抽象出来,然后回退到更通用的参数名称 vars
。此外,与其依赖在全局或包含范围内定义的宏变量,不如在调用期间传入列表。您是正确的,space 分隔列表可以在宏中使用 %do
循环迭代,其上限是列表中 'words' 的 countw
数量——你的语法只是有点偏差。
你不必宏观化一切,体育逻辑的额外宏观化已经很远了。请记住,宏调用发出(或生成)输入 SAS 提交系统的源代码。宏编码编码过程比较抽象或者toolboxy有时也被称为codegen。
您的原始代码可能有错误,因为您评估(在一行中)多个特殊的 kid 变量并对相同的 2 个变量(talent_type
和 type_name
)执行赋值,因此可能会覆盖先前分配的值。有时,这样的评估和分配是 OUTPUT
分隔行。
%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)
总而言之,在开始宏编码之前,请确保您的数据整形和评估处理方法是坚如磐石的。如果您问自己 我应该对此进行宏设置吗?,请保守一点并回答否。对维护者和未来的自己友好,不要让事情过于复杂。
您的代码几乎不需要调整,我做了一些更改。此外,当我们使用 %if 时,我们总是使用宏变量。否则我们最好只使用带有普通数据集变量的 if 语句。
%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;