如何对字符变量中的单词进行重复数据删除?

时间:2015-11-10 22:36:25

标签: sas

我有一个变量,其中包含我将要用于进程的单词列表,并且需要保留在一个变量中(至少,在此问题/答案结束时需要返回在一个变量)。我需要对要删除重复的单词列表。

对变量进行重复数据删除的最有效方法是什么?我可以不将变量拆分成多个变量吗?

例如,我有这个数据集:

data want;
  x = "A B C D E F G H I J K";
run;

我希望返回此数据集。

data want;
  set have;
  array myvar /* the variables I do not have*/ ;
  call sortc(of myvar[*]);
run;

如果我有多个变量,我可以这样做

call scan

但是这不仅仅适用于一个变量,而是对该变量中的单词进行排序。

实际字符串的长度可能超过一个字符,如果相关(请不要提供适用于一个字符的解决方案)。单词不需要按任何特定的顺序排序,你删除的副本是无关紧要的 - " C F E G H I A B D J K"和" A B C D E F G H I J K"同样有效。或任何其他组合。

4 个答案:

答案 0 :(得分:3)

只需添加新列表中尚未包含的每个单词,即可构建新列表。如果需要,可以指定要在函数调用中使用的分隔符列表。

data have;
  old = 'A B C D E F E G H B I A B D J K';
run;

data want ;
  set have;
  length word new $200 ;
  do i=1 to countw(old);
    word=scan(old,i);
    if indexw(new,word) then continue;
    new=catx(' ',new,word);
  end;
  put (old new) (=/);
run;

old=A B C D E F E G H B I A B D J K
new=A B C D E F G H I J K

答案 1 :(得分:1)

此问题的一个解决方案包括使用findw迭代单词,并使用data have; x = "A B C D E F E G H B I A B D J K"; *initialize dataset; do count = countw(x) to 2 by -1; *iterate over words (right to left here); call scan(x,count,position,length); *look for the first word; _curword = substr(x,position,length); *for simplicity, I make a temporary variable with the current word and the current rest of string. This could be done without these two variables just including them in the `findw` itself.; _restofstring = substr(x,1,position-1); *The remaining (to the left) portion of the string that could have duplicates; put "|"_curword "|"_restofstring "|"; put position= length=; if findw(_restofstring,trim(_curword)) then do; *If a duplicate is found; put "Deleting" _curword=; *delete it below; x = substr(x,1,position-1) || substr(x,position+length+1); end; end; put x=; run; 将其与剩余的子字符串进行比较,以删除重复项。

flexslider

答案 2 :(得分:1)

您可以将每个单词输出到单独的记录中,对其进行排序&删除重复项,然后展平回到单个记录。

data have ;
  x = "A B C D E F E G H B I A B D J K" ;
  id = _n_ ;
  do i = 1 to countw(x) ;
    word = scan(x,i,' ') ;
    output ;
  end ;
run ;

proc sort data=have nodupkey ;
  by id word ;
run ;

data want ;
  set have ;
  by id ;
  length x $200. ; /* same length as 'x' in have dataset */
  retain x '' ;
  if first.id then call missing(x) ;
  x = catx(' ',x,word) ;
  if last.id then output ;
run ;

你可以利用proc fcmp和宏的力量创建一个宏功能三明治,从而进一步发展这个阶段:

proc fcmp outlib=work.funcs.utility ;
  function dedupe(string $) $ ;
    length string $200 ;
    rc = run_macro('DEDUPE',string) ; /* call dedupe macro */
    if rc = 0 then return(strip(string)) ;
    else return('') ;
  endsub ;
quit ;
options cmplib=work.funcs ;

%MACRO DEDUPE ;
  data __dedupe ; 
    x = &STRING ; /* passed from proc fcmp with quotes */
    do i = 1 to countw(x) ;
      word = scan(x,i,' ') ;
      output ;
    end ;
  run ;
  proc sort data=__dedupe nodupkey ;
    by word ;
  run ;
  data _null_ ;
    set __dedupe end=eof ;
    length x $200 ;
    retain x '' ;
    x = catx(' ',x,word) ;
    if eof then call symput('STRING',strip(x)) ; /* return &STRING to proc fcmp */
  run ;
  /* cleanup */
  proc sql noprint ;
    drop table __dedupe ;
  quit ;
%MEND ;

一旦定义,您就可以像使用任何其他datastep函数一样使用它。在PROC FCMP中调用的宏的美妙之处在于它们独立于“on-the-side”运行,远离调用该函数的datastep。

data want ;
  x = "A B C D E F E G H B I A B D J K" ;
  x2 = dedupe(x) ;
run ;

然后您可以将FCMP函数包装在另一个宏中,并在%SYSFUNC内调用该函数,这样您就可以对宏变量执行相同的处理:

%MACRO STRDEDUPE(STR) ;
  %SYSFUNC(dedupe(&STR))
%MEND ;

%LET X = A B C D E F E G H B I A B D J K ;
%PUT %STRDEDUPE(&X) ;

PROC FCMP程序> https://support.sas.com/documentation/cdl/en/proc/61895/HTML/default/viewer.htm#a002890483.htm

在功能型宏中使用SAS®的全功能(SUGI Paper,2012)> https://support.sas.com/resources/papers/proceedings12/004-2012.pdf

[未经测试的代码,如果有任何错误,请告诉我们]

答案 3 :(得分:0)

data have;
  x = "A B C D E F E G H B I A B D J K";
  do i=1 to countw(x); 
  _x=prxchange('s/(\b\w+?\b)(.*?)(?=\1{1,})(.?)/$2 $3/i',-1,x);
  x=_x;
  end;
 drop i;
run;
proc print;
run;