- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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.
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.
Accepted Solutions
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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));
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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;
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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));
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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.
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
@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
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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. : )
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.