DATA Step, Macro, Functions and more

Remove items from a list (string processing)

Accepted Solution Solved
Reply
PROC Star
Posts: 1,322
Accepted Solution

Remove items from a list (string processing)

[ Edited ]

Often I have a list of items:

%let list=Monday Tuesday Wednesday Thursday Friday Saturday;

And I want to remove n items from the list.  So suppose I want to remove Tuesday and Thursday.  You can do it with TRANWRD(), but if you are removing multiple words, it gets ugly fast if you nest them, and feels like it shouldn't need two function calls.

 

%let list2=%sysfunc(tranwrd(%sysfunc(tranwrd(&list,Tuesday,)),Thursday,));
%put &list2;

Sometimes when I have faced this I have written a little function-style macro to loop through the items of a list, checking to see if each item is in the list of items to remove.  Something like:

%macro removeitem(list=,remove=);
  %local
    i
    item_i
    return
  ;
  %do i=1 %to %sysfunc(countw(&list,%str( )));
    %let item_i=%scan(&list,&i,%str( ));
    %if %sysfunc(findw(&remove,&item_i))=0 %then %let return=&return &item_i;
  %end;
  &return
%mend;

%let list3=%RemoveItem(list=&list,remove=Tuesday Thursday);
%put &list3;

 

Above approaches work, but I never feel good about them.  I always assume there is a function I'm not thinking of, like a REMOVE() function, or one of the TRANSTRN/TRANWRD functions that would allow me to pass a list of strings to replace and a list of replacement strings, like TRANSLATE() allows.

 

Or maybe today's the day that I dive into regular expressions? 

 

I think of this as a macro problem, because that's usually where I encounter such lists, but if there is a nifty data step solution, happy to see that, especially if in can be macrified (macrocized?)

 

Thanks,

--Q.


Accepted Solutions
Solution
4 weeks ago
PROC Star
Posts: 102

Re: Remove items from a list (string processing)

@Quentin:

One possibility is to use PRXCHANGE instead, e.g.:

%let list=Monday Tuesday Wednesday Thursday Friday Saturday;
%let list2=%sysfunc(prxchange(s/Tuesday|Thursday//,-1,&list));

View solution in original post


All Replies
Super User
Posts: 5,509

Re: Remove items from a list (string processing)

Perhaps it's just a small piece of the puzzle, but you can simplify the list processing.  Instead of accumulating the items into a list, just generate the "non-removed" items one word at a time.  In this case:

 

%macro removeitem(list=,remove=);
  %local
    i
    item_i
  ;
  %do i=1 %to %sysfunc(countw(&list,%str( )));
    %let item_i=%scan(&list,&i,%str( ));
    %if %sysfunc(findw(&remove,&item_i))=0 %then &item_i;
  %end;
%mend;

%let list3=%RemoveItem(list=&list,remove=Tuesday Thursday);
%put &list3;

Solution
4 weeks ago
PROC Star
Posts: 102

Re: Remove items from a list (string processing)

@Quentin:

One possibility is to use PRXCHANGE instead, e.g.:

%let list=Monday Tuesday Wednesday Thursday Friday Saturday;
%let list2=%sysfunc(prxchange(s/Tuesday|Thursday//,-1,&list));
PROC Star
Posts: 1,322

Re: Remove items from a list (string processing)

Thanks @s_lassen that's nifty approach.

 

I added a Ballot idea for a ReplaceW() function.  Not sure if it's really feasible, but I think it's what I want.

 

https://communities.sas.com/t5/SASware-Ballot-Ideas/Create-ReplaceW-character-function-that-accepts-...

 

 

PROC Star
Posts: 7,474

Re: Remove items from a list (string processing)

@Quentin: While I agree that regular expressions are a lot more powerful and well worth learning, you can always simplify the task in a data step by using a do loop. Still uses multiple uses of the tranwrd function, but easier (for me at least) to read. e.g.:

data have (drop=i);
  informat days $70.;
  length i $10;
  input days &;
  do i='Monday','Wednesday','Friday';
    days=tranwrd(days,i,'');
  end;
  cards;
Monday Tuesday Wednesday Wednesday Friday
Monday Tuesday Thursday Monday Sunday
;
run;

Art, CEO, AnalystFinder.com

 

PROC Star
Posts: 1,322

Re: Remove items from a list (string processing)

[ Edited ]

Agree @art297,  the looping structure is much easier on the eyes.  Even more so in the macro setting.  I was prompted to start this thread because I had started with one replacement, then two, then three.  And ended up with to following atrocity in my code:

 

%let list=These SomeWordToRemove are SomeOtherWordToRemove the YetAnotherWordToRemove words to keep;
%put %sysfunc(tranwrd(%sysfunc(tranwrd(%sysfunc(tranwrd(&list,SomeWordToRemove,)),SomeOtherWordToRemove,)),YetAnotherWordToRemove,)) ;

 

 

I promised myself I would take the time to refactor it into a little function-style macro that does looping as you illustrated. : )

☑ This topic is solved.

Need further help from the community? Please ask a new question.

Discussion stats
  • 5 replies
  • 233 views
  • 5 likes
  • 4 in conversation