BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.

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.

BASUG is hosting free webinars Next up: Jane Eslinger presenting PROC REPORT and the ODS EXCEL destination on Mar 27 at noon ET. Register now at the Boston Area SAS Users Group event page: https://www.basug.org/events.
1 ACCEPTED SOLUTION

Accepted Solutions
s_lassen
Meteorite | Level 14

@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

5 REPLIES 5
Astounding
PROC Star

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;

s_lassen
Meteorite | Level 14

@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));
Quentin
Super User

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-...

 

 

BASUG is hosting free webinars Next up: Jane Eslinger presenting PROC REPORT and the ODS EXCEL destination on Mar 27 at noon ET. Register now at the Boston Area SAS Users Group event page: https://www.basug.org/events.
art297
Opal | Level 21

@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

 

Quentin
Super User

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. : )

BASUG is hosting free webinars Next up: Jane Eslinger presenting PROC REPORT and the ODS EXCEL destination on Mar 27 at noon ET. Register now at the Boston Area SAS Users Group event page: https://www.basug.org/events.

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

Register now!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

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