SAS Programming

DATA Step, Macro, Functions and more
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.

The Boston Area SAS Users Group is hosting free webinars!
Next up: Troy Martin Hughes presents Calling Open-Source Python Functions within SAS PROC FCMP: A Google Maps API Geocoding Adventure on Wednesday April 23.
Register now at 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-...

 

 

The Boston Area SAS Users Group is hosting free webinars!
Next up: Troy Martin Hughes presents Calling Open-Source Python Functions within SAS PROC FCMP: A Google Maps API Geocoding Adventure on Wednesday April 23.
Register now at 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. : )

The Boston Area SAS Users Group is hosting free webinars!
Next up: Troy Martin Hughes presents Calling Open-Source Python Functions within SAS PROC FCMP: A Google Maps API Geocoding Adventure on Wednesday April 23.
Register now at https://www.basug.org/events.

sas-innovate-white.png

Special offer for SAS Communities members

Save $250 on SAS Innovate and get a free advance copy of the new SAS For Dummies book! Use the code "SASforDummies" to register. Don't miss out, May 6-9, in Orlando, Florida.

 

View the full agenda.

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

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