引用宏内部的数组元素循环

时间:2015-04-13 06:11:51

标签: arrays sas sas-macro

我可以VIO无误地调用宏%VIO(Dow=Fri,Hour=8)。现在我想在do循环中嵌入调用宏。

这是我尝试过的但没有运气。

%macro trythis;
  data _null_;
    array ay[3] $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 $3.;
    dow = "&Dow";
  run;
%mend;

似乎ay[&i]将解析为ay[1]而不是Fri

1 个答案:

答案 0 :(得分:1)

您不能以这种方式与宏变量交换数据。宏变量和宏调用在数据步骤甚至编译之前解析,更不用说运行了。这很好,因为它允许宏变量和宏影响数据步骤编译(例如,定义存在哪些列)。这也意味着你无法做你想做的事情。尽管有相似之处,SAS Macro语言不是在SAS中编写函数的方法。你可以编写某些函数式宏,但这不是一回事。

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

如果您的宏接受一个值并使用宏语言处理它,并且您需要与数据步骤进行交互,那么您有几个选项:

  1. 用FCMP(SAS的函数编写语言)重写宏
  2. 重写宏以使用宏中的数据步骤而不是宏语言元素,只需要能够获取数组元素的名称而不是其值作为参数
  3. 使用多个数据步骤完成任务
  4. 使用RUN_MACRO和/或DOSUBL(可能与FCMP结合使用)。这很可能是最慢的方法,但它也与您尝试做的最相似。迪伦埃利斯' RUN_MACRO Run!详细解释了这种方法。

  5. 如果您不需要与数据步骤进行互动,这可能会更容易。

    宏数组与数据步骤数组完全相同。它们不是编程语言的实际特征;他们是一个黑客。你可以在互联网上搜索他们的论文;例如,Tight Looping with Macro Arrays解释了一个例子。

    但是,一般原则非常简单。你使用多个&符号来解决问题。

    %let ay1 = Fri;
    %let ay2 = Sat;
    %let ay3 = Sun;
    
    %let i=2;
    
    %put &&ay&i.;
    

    这将按照您的预期解决。双&符号告诉SAS延迟一次通过,因此&&ay&i&ay1结算时变为&i但双&&只会更改为单&和{只留下{1}}。

    所以你可以用do循环做一些简单的事情:

    ay

    现在,我想非常清楚地说明:从易于编程的角度和速度的角度来看,你在这里采取的一般方法很可能很差。你没有透露%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; 的可见性,因此很难说出你正在做什么或做出正确的做法,但这很可能不是正确的做法。至少,将所有部分分成三个或四个明显基本相互依赖的宏将导致维护的复杂性,并且反复运行带有单个where子句的datastep非常非常慢。