在宏 do 循环中引用数组元素
quote array element inside macro do loop
我可以通过 %VIO(Dow=Fri,Hour=8)
调用宏 VIO
而不会出错。现在我想将调用宏嵌套在 do 循环中。
这是我尝试过但没有成功的方法。
%macro trythis;
data _null_;
array ay[3] ('Fri' 'Sat' 'Sun');
%do i = 1 %to dim(ay);
%do j = 1 %to 24;
%VIO(ay[&i],&j);
%end;
%end;
run;
%mend;
%macro VIO(Dow,Hour);
data Want&Dow.&Hour;
set have(where=(hour="&Hour"));
format dow .;
dow = "&Dow";
run;
%mend;
似乎 ay[&i]
将解析为 ay[1]
而不是 Fri
。
你不能那样用宏变量交换数据。宏变量和宏调用甚至在数据步骤被编译之前就解析了,更不用说 运行 了。这很好,因为它允许宏变量和宏影响数据步骤编译(例如,定义存在哪些列)。这也意味着你不能做你想做的事。尽管有相似之处,但 SAS 宏语言 不是 一种在 SAS 中编写函数的方法。您可以编写某些函数样式的宏,但这不是一回事。
您没有指定宏的作用,因此很难完全回答如何修复这个问题。
如果您的宏采用一个值并以宏语言对其进行操作,并且您需要与数据步骤进行交互,您有多种选择:
- 用 FCMP(SAS 的函数编写语言)重写您的宏
- 重写您的宏以使用宏中的数据步骤而不是宏语言元素,其中需要能够将数组元素的名称而不是其值作为参数
- 使用多个数据步骤来完成您的任务
- 使用RUN_MACRO and/or DOSUBL(可能结合FCMP)。这很可能是 最慢的 方法,但它也与您尝试执行的操作最相似。 Dylan Ellis 的 RUN_MACRO Run! 详细解释了此方法。
如果您不需要与数据步骤交互,这可能更容易做到。
宏数组与数据步长数组不太一样。它们不是编程语言的实际功能;他们是黑客。您可以在互联网上搜索有关它们的论文;例如,Tight Looping with Macro Arrays 解释了一个例子。
不过,一般原则非常简单。您使用多个 & 符号乘以解决某些问题。
%let ay1 = Fri;
%let ay2 = Sat;
%let ay3 = Sun;
%let i=2;
%put &&ay&i.;
这将如您所愿地解决。双符号告诉 SAS 延迟解析一次,因此当 &i
解析时 &&ay&i
变为 &ay1
但双 &&
只是变为单个 &
和 ay
一个人呆着。
所以你可以用 do 循环做一些简单的事情:
%macro trythis;
%let ay1=Fri;
%let ay2=Sat;
%let ay3=Sun;
%do i = 1 %to 3;
%do j = 1 %to 24;
%VIO(&&ay&i.,&j);
%end;
%end;
%mend;
现在,我想非常清楚地说明:无论是从易于编程的角度还是从速度的角度来看,您在这里采用的一般方法很可能是一个糟糕的方法。您没有让 %vio
可见,因此很难说您在做什么或正确的方法是什么,但这很可能不是正确的方法。至少,将所有部分拆分为明显相互依赖的三个或四个宏将导致维护复杂性,并且重复 运行 使用单个 where 子句连接数据步骤非常非常慢。
我可以通过 %VIO(Dow=Fri,Hour=8)
调用宏 VIO
而不会出错。现在我想将调用宏嵌套在 do 循环中。
这是我尝试过但没有成功的方法。
%macro trythis;
data _null_;
array ay[3] ('Fri' 'Sat' 'Sun');
%do i = 1 %to dim(ay);
%do j = 1 %to 24;
%VIO(ay[&i],&j);
%end;
%end;
run;
%mend;
%macro VIO(Dow,Hour);
data Want&Dow.&Hour;
set have(where=(hour="&Hour"));
format dow .;
dow = "&Dow";
run;
%mend;
似乎 ay[&i]
将解析为 ay[1]
而不是 Fri
。
你不能那样用宏变量交换数据。宏变量和宏调用甚至在数据步骤被编译之前就解析了,更不用说 运行 了。这很好,因为它允许宏变量和宏影响数据步骤编译(例如,定义存在哪些列)。这也意味着你不能做你想做的事。尽管有相似之处,但 SAS 宏语言 不是 一种在 SAS 中编写函数的方法。您可以编写某些函数样式的宏,但这不是一回事。
您没有指定宏的作用,因此很难完全回答如何修复这个问题。
如果您的宏采用一个值并以宏语言对其进行操作,并且您需要与数据步骤进行交互,您有多种选择:
- 用 FCMP(SAS 的函数编写语言)重写您的宏
- 重写您的宏以使用宏中的数据步骤而不是宏语言元素,其中需要能够将数组元素的名称而不是其值作为参数
- 使用多个数据步骤来完成您的任务
- 使用RUN_MACRO and/or DOSUBL(可能结合FCMP)。这很可能是 最慢的 方法,但它也与您尝试执行的操作最相似。 Dylan Ellis 的 RUN_MACRO Run! 详细解释了此方法。
如果您不需要与数据步骤交互,这可能更容易做到。
宏数组与数据步长数组不太一样。它们不是编程语言的实际功能;他们是黑客。您可以在互联网上搜索有关它们的论文;例如,Tight Looping with Macro Arrays 解释了一个例子。
不过,一般原则非常简单。您使用多个 & 符号乘以解决某些问题。
%let ay1 = Fri;
%let ay2 = Sat;
%let ay3 = Sun;
%let i=2;
%put &&ay&i.;
这将如您所愿地解决。双符号告诉 SAS 延迟解析一次,因此当 &i
解析时 &&ay&i
变为 &ay1
但双 &&
只是变为单个 &
和 ay
一个人呆着。
所以你可以用 do 循环做一些简单的事情:
%macro trythis;
%let ay1=Fri;
%let ay2=Sat;
%let ay3=Sun;
%do i = 1 %to 3;
%do j = 1 %to 24;
%VIO(&&ay&i.,&j);
%end;
%end;
%mend;
现在,我想非常清楚地说明:无论是从易于编程的角度还是从速度的角度来看,您在这里采用的一般方法很可能是一个糟糕的方法。您没有让 %vio
可见,因此很难说您在做什么或正确的方法是什么,但这很可能不是正确的方法。至少,将所有部分拆分为明显相互依赖的三个或四个宏将导致维护复杂性,并且重复 运行 使用单个 where 子句连接数据步骤非常非常慢。