在宏 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 中编写函数的方法。您可以编写某些函数样式的宏,但这不是一回事。

您没有指定宏的作用,因此很难完全回答如何修复这个问题。

如果您的宏采用一个值并以宏语言对其进行操作,并且您需要与数据步骤进行交互,您有多种选择:

  1. 用 FCMP(SAS 的函数编写语言)重写您的宏
  2. 重写您的宏以使用宏中的数据步骤而不是宏语言元素,其中需要能够将数组元素的名称而不是其值作为参数
  3. 使用多个数据步骤来完成您的任务
  4. 使用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 子句连接数据步骤非常非常慢。