空格分隔列表交集

时间:2018-01-22 09:53:26

标签: sas sas-macro

注意:来自@ user667489的备注后编辑的代码但问题仍然存在。

我构建了一个相当简单的宏来返回2个空格分隔列表的交集作为新的空格分隔列表,但由于某种原因,宏的定义会返回错误。

宏遍历两个列表并在找到匹配时保留一个元素(非常简单,不处理重复或优化)。

我无法理解日志,它显示以下错误消息的组合:

  

错误:宏关键字LET显示为文本。

     

错误:宏关键字MACRO显示为文本。

%macro list_intersection
(list1= /* space separated list, or unique term */
,list2= /* space separated list, or unique term */
);
%local output;
%local i;
%local j;
%let i = 1;
%let j = 1;
%do %while (%length(%scan(&list1,&i)));
  %do %while (%length(%scan(&list2,&j)));
    %if (%scan(&list1,&i) = %scan(&list2,&j)) %then
      %let output = &output %scan(&list1,&i);
    %let j = %eval(&j+1);
  %end;
  %let i = %eval(&i+1);
%end;
&output
%mend;

你能帮助我解决这个问题吗?

我也愿意采用更有效/更强大/更简单的方式来实现相同的输出。

可重复日志

使用SAS 9.3,我将上面的代码放在一个单独的程序中,以免被污染,保存项目,关闭并重新打开。打开程序,单击运行按钮,这是完整的日志:

1                                                          The SAS System                             09:50 Monday, January 22, 2018

1          ;*';*";*/;quit;run;
2          OPTIONS PAGENO=MIN;
3          %LET _CLIENTTASKLABEL='Program3';
ERROR: Macro keyword LET appears as text.
4          %LET _CLIENTPROJECTPATH='F:\CI\Projects\Wealth Indicators\106 Explore DIM_PHYSICALPERSON\SAS\Rework_table_auto2.egp';
ERROR: Macro keyword LET appears as text.
5          %LET _CLIENTPROJECTNAME='Rework_table_auto2.egp';
ERROR: Macro keyword LET appears as text.
6          %LET _SASPROGRAMFILE=;
ERROR: Macro keyword LET appears as text.
7          
8          ODS _ALL_ CLOSE;
9          OPTIONS DEV=ACTIVEX;
10         GOPTIONS XPIXELS=0 YPIXELS=0;
11         FILENAME EGSR TEMP;
12         ODS tagsets.sasreport13(ID=EGSR) FILE=EGSR STYLE=HtmlBlue
12       ! STYLESHEET=(URL="file:///C:/Program%20Files/SASHome/x86/SASEnterpriseGuide/5.1/Styles/HtmlBlue.css") NOGTITLE NOGFOOTNOTE
12       !  GPATH=&sasworklocation ENCODING=UTF8 options(rolap="on");
13         
14         GOPTIONS ACCESSIBLE;
15             %macro list_intersection
ERROR: Macro keyword MACRO appears as text.
16             (list1= /* space separated list, or unique term */
17             ,list2= /* space separated list, or unique term */
18             );
19             %local output;
ERROR: Macro keyword LOCAL appears as text.
20             %local i;
ERROR: Macro keyword LOCAL appears as text.
21             %local j;
ERROR: Macro keyword LOCAL appears as text.
22             %let i = 1;
ERROR: Macro keyword LET appears as text.
23             %let j = 1;
ERROR: Macro keyword LET appears as text.
24             %do %while (%length(%scan(&list1,&i)));
ERROR: Macro keyword DO appears as text.
25               %do %while (%length(%scan(&list2,&j)));
ERROR: Macro keyword DO appears as text.
26                 %if (%scan(&list1,&i) = %scan(&list2,&j)) %then
ERROR: Macro keyword IF appears as text.
27                   %let output = &output %scan(&list1,&i);
28              %let j = %eval(&j+1);
ERROR: Macro keyword LET appears as text.
29               %end;
ERROR: Macro keyword END appears as text.
30               %let i = %eval(&i+1);
ERROR: Macro keyword LET appears as text.
31             %end;
ERROR: Macro keyword END appears as text.
32             &output
33             %mend;
ERROR: Macro keyword MEND appears as text.
34         
35         GOPTIONS NOACCESSIBLE;
36         %LET _CLIENTTASKLABEL=;
ERROR: Macro keyword LET appears as text.
37         %LET _CLIENTPROJECTPATH=;
2                                                          The SAS System                             09:50 Monday, January 22, 2018

ERROR: Macro keyword LET appears as text.
38         %LET _CLIENTPROJECTNAME=;
ERROR: Macro keyword LET appears as text.
39         %LET _SASPROGRAMFILE=;
ERROR: Macro keyword LET appears as text.
40         
41         ;*';*";*/;quit;run;
42         ODS _ALL_ CLOSE;
43         
44         
45         QUIT; RUN;
46     

编辑前的初始代码:

%macro list_intersection
    (list1= /* space separated list, or unique term */
    ,list2= /* space separated list, or unique term */
    );
    %local output =;
    %local i = 1;
    %local j = 1;
    %do %while (%length(%scan(&list1,&i)));
      %do %while (%length(%scan(&list2,&j)));
        %if (%scan(&list1,&i) = %scan(&list2,&j) %then
          %local output = &output %scan(&list1,&i);
        %let j = %eval(&j+1);
      %end;
      %let i = %eval(&i+1);
    %end;
    &output
    %mend;

2 个答案:

答案 0 :(得分:2)

一些事情立即脱颖而出:

  1. 您无法使用%local为宏变量设置值。您必须编写两个单独的语句%local i=1;,而不是%local i; %let i = 1;%local将宏变量初始化为空字符串。
  2. 您的%if声明中有不平衡的括号。
  3. 尝试将%let j = %eval(&j+1);移动到外部%do %while循环中。
  4. 此外,您可能希望确保%scan仅将空格用作分隔符 - 默认为空格加. < ( + & ! $ * ) ; ^ - / , % |
  5. 这是一个有效的版本:

    %macro list_intersection
    (list1= /* space separated list, or unique term */
    ,list2= /* space separated list, or unique term */
    );
    %local output;
    %local i;
    %local j;
    %let i = 1;
    %do %while (%length(%scan(&list1,&i,%str( ))));
      %let j = 1;
      %do %while (%length(%scan(&list2,&j,%str( ))));
        %if %scan(&list1,&i,%str( )) = %scan(&list2,&j,%str( )) %then
          %let output = &output %scan(&list1,&i,%str( ));
        %let j = %eval(&j+1);
      %end;
      %let i = %eval(&i+1);
    %end;
    &output
    %mend;
    
    %put %list_intersection(list1=1 2 3,list2=2 3 4);
    

答案 1 :(得分:1)

您可以使用SAS功能更轻松。使用COUNTW()函数查找%DO循环的上限。使用FINDW()功能测试是否在其他列表中找到了单词。

%macro list_intersection
(list1 /* space separated list of terms */
,list2 /* space separated list of terms */
);
%local output i next ;
%do i=1 %to %sysfunc(countw(&list1,%str( ))) ;
  %let next=%scan(&list1,&i,%str( ));
  %if %sysfunc(findw(&list2,&next,,s)) %then %let output=&output &next ;
%end;
&output
%mend;

您可以在i调用中添加findw()修饰符,使其不区分大小写。您还可以测试该单词是否已在输出字符串中以消除重复项。

%macro list_intersection_nodups
(list1 /* space separated list of terms */
,list2 /* space separated list of terms */
);
%local output i next ;
%do i=1 %to %sysfunc(countw(&list1,%str( ))) ;
  %let next=%scan(&list1,&i,%str( ));
  %if %sysfunc(findw(&list2,&next,,si)) and not %sysfunc(findw(&output,&next,,si))
  %then %let output=&output &next ;
%end;
&output
%mend;

示例:

274  %put %list_intersection_nodups(A B a C,a c d);
A C