SAS宏变量+数组索引

时间:2011-03-28 08:57:57

标签: sas sas-macro

这与此问题有关:SAS macro variable change

以下代码解释了问题:

%macro test (arg=); 
    options  mlogic mprint symbolgen;
    array arraytwo [%EVAL(&arg+1)] _temporary_;
    sum=0;
    %do i = 1 %to %EVAL(&arg+1);
        sum=sum+&i;
        arraytwo[&i]=sum;
        %end;
    return=arraytwo[&arg+1];
    %mend test;

/* This is ok */
data dat1;
    %test(arg=9);
run;

data dat2;
    input M;
    cards;
5
6
7
;
run;

/* This give an error= A character operand was found in the %EVAL function or %IF condition where a numeric
operand is required. The condition was: M+1 */
data dat3;
    set dat2;
    %test(arg=M);
run;

所以问题是为什么它在最后一次测试中会出错?感谢。

2 个答案:

答案 0 :(得分:4)

如果您正好使用SAS 9.2或更高版本,您可能需要查看proc fcmp以创建执行此操作的函数。

如果将其作为函数而不是宏编写,则可以传入将解析为数值的数据集变量 - 或直接传递数值。例如,尝试以下代码:

proc fcmp outlib=work.funcs.simple;
  function sumloop(iter);
    x=1;
    do i=1 to iter+1;
      x+i;
    end;
    return(x);
  endsub;
run;

/* point to the location the function was saved in */
option cmplib=work.funcs; 

data _null_;
  input M;
  y=sumloop(M); /* data set variable */
  z=sumloop(9); /* static numeric value */
  put M= @7 y= @14 z= @20 ;
cards;
1
2
3
4
5
6
7
8
9
;
run;

/* My log looks like this:

14   data _null_;
15       input M;
16       y=sumloop(M); /* data set variable */
17       z=sumloop(9); /* static numeric value */
18       put M= @7 y= @14 z= @20 ;
19       cards;

M=1   y=3    z=55
M=2   y=6    z=55
M=3   y=10   z=55
M=4   y=15   z=55
M=5   y=21   z=55
M=6   y=28   z=55
M=7   y=36   z=55
M=8   y=45   z=55
M=9   y=55   z=55
*/

答案 1 :(得分:2)

我不得不说我不完全确定你要做什么;但这会给你带来你想要的结果吗?上面代码的问题在于您尝试组合数据集变量和宏变量的方式 - 这并不像人们希望的那样容易......

%macro test (argList=, totNumObs=);
    %local arg;
    %local j;
    %local i;
    %do j = 1 %to &totNumObs;
        %let arg = %scan(&argList, &j); 
        array array&j [%EVAL(&arg+1)] _temporary_;
        sum = 0;
        %do i = 1 %to %EVAL(&arg+1);
            sum = sum+&i;
            array&j[&i] = sum;
        %end;
        return = array&j[&arg+1];
        output;
    %end;
%mend test;

data dat2;
    input M;
    cards;
5
6
7
;
run;

proc sql noprint;
    select 
        count (*) into :numObs 
    from dat2 ;
    select 
        M into :listofMs separated by ' '
    from dat2
    order by M;
quit;

options  mlogic mprint symbolgen;

data dat3;
    %test(argList= &listofMs, totNumObs= &numObs);
run;

proc print data= dat3;
run;