space 分隔列表交集

space separated list intersection

注意:根据@user667489 的评论对代码进行了编辑,但问题仍然存在。

我构建了一个相当简单的宏来 return 2 space 分隔列表的交集作为一个新的 space 分隔列表但是由于某些原因宏的定义 returns 个错误。

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

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

ERROR: Macro keyword LET appears as text.

ERROR: Macro keyword MACRO appears as text.

%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;

你能帮我圈出这个问题吗?

我也愿意接受一种更 efficient/robust/simple 的方式来实现相同的输出。

可重现日志

使用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 Indicators6 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;

有几件事立即脱颖而出:

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

这是一个工作版本:

%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);

您可以使用 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;

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

%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