Using substr, IN on array elements in MACRO

Accepted Solution Solved
Reply
Contributor
Posts: 21
Accepted Solution

Using substr, IN on array elements in MACRO

Hello SAS community,

 

I've built some code in data steps that I am now going to have to repeat on many other data sources, so I'm changing the code over to %macro in order to easily apply it many times. However I've run into an issue.

 

First i will show the original code snippet, then I will show a toy example I am playing with to find out exactly what is causing the problem:

 

%do j=1 %to &d;
  %if %substr(array{j},1,5) in ("str1", "str2", "str3") %then %do;
      if var1 > 3 then var2="no";
  %end;
%end;

THis produces error4:

"Macro function %substr has too many arguments. The excess arguments will be ignored.

A character operand was found in the %EVAL function or %IF condition where a number operand is required. The condition was: j}

Argument 2 to macro function %substr is not a number.

Operand missing for IN operator to argument to %EVAL function"

 

So one of the first things I realised when converting code to macros is that the %dos and %ifs need to have percent prefix to avoid issues, then i found out that substr() is not valid in macros, so you ahve to use either %substr or %sysfunc(substr()). Then I learned that "IN" is also not valid, unless you include options to allow it before code. 

 

GIven these lessons, I have tried to now use a toy example just to test out the general functionality of declaring array elements and checking substr of the value of them using "in" operand. Here's my test code:

 

data test;
input id $ answer1 $ answer2 $;
datalines;
1 yes maybe 
2 no maybe
3 maybe maybe
;
run;

options minoperator mindelimiter=',';
%macro substringtest();

data test2;
set test;
array answer{2};

%do i=1 %to 2;
%if %substr(answer{i},1,1) in ("y", "n") %then %do;
certain&i=1;
%end;
%else %do;
certain&i=0;
%end;
%end;

run;
%mend;

%substringtest;

When running this, I get no mlogic issues, but the values for obs 1 and 2 "certain1" should be "1", but they are all 0 for certain1 and certain2.

 

I'm now a little confused regarding a few things

 

1) Why is the substr argument workign in test code but no the real code.

2) Why isn't the test code producing proper variable outputs reflecting correct logic.

3) Is there some easier way to get around using do blocks? I have other macros I converted to which uses substr and arrays and in just fine, but because i have further conditions after, i have some parts that are in "do" blocks. Maybe there's a workaround to just not do this?

 

Thanks ahead of time.


Accepted Solutions
Solution
‎10-17-2016 07:03 AM
Super User
Posts: 5,516

Re: Using substr, IN on array elements in MACRO

Posted in reply to chrisengel

If you're using DATA step code, arrays might look like this:

 

array answer {2};

array certain {2};

do i=1 to dim(answer);

   if substr(answer{i}, 1, 1) in ('n', 'y') then certain{i}=1;

   else certain{i}=0;

end;

 

Even that could likely be simplified by removing SUBSTR entirely.  It all depends on what might be found in the ANSWER variables.  If macro language were to be inserted into this program, it would only be to define the array dimensions:  {&d}

 

If you to use macro language instead of arrays, it might look like this:

 

%do i=1 %to 2;

   if substr(answer&i 1, 1) in ('n', 'y') then certain&i=1;

   else certain&i=0;

%end;

 

Macro language is not processing your data.  It is generating the proper SAS statements needed to process your data once the DATA step begins to execute.

View solution in original post


All Replies
Super User
Posts: 19,867

Re: Using substr, IN on array elements in MACRO

Posted in reply to chrisengel

There's nothing in your loop that requires a macro. If you're in a data step use a regular do loop. 

 

Use a macro do loop to repeat procedures. 

 

Your code below would change to declare a certain array as well. 

 

If this doesn't reflect your actual situation then please make an example that's relevant. 

 

1. macro comparisons don't include quotes. in y, n http://support.sas.com/kb/35/591.html

2. Your evaluation is never hitting true. Add %put to,each %if condition so you can trace your logic. 

3. See stuff before this. 

 

Solution
‎10-17-2016 07:03 AM
Super User
Posts: 5,516

Re: Using substr, IN on array elements in MACRO

Posted in reply to chrisengel

If you're using DATA step code, arrays might look like this:

 

array answer {2};

array certain {2};

do i=1 to dim(answer);

   if substr(answer{i}, 1, 1) in ('n', 'y') then certain{i}=1;

   else certain{i}=0;

end;

 

Even that could likely be simplified by removing SUBSTR entirely.  It all depends on what might be found in the ANSWER variables.  If macro language were to be inserted into this program, it would only be to define the array dimensions:  {&d}

 

If you to use macro language instead of arrays, it might look like this:

 

%do i=1 %to 2;

   if substr(answer&i 1, 1) in ('n', 'y') then certain&i=1;

   else certain&i=0;

%end;

 

Macro language is not processing your data.  It is generating the proper SAS statements needed to process your data once the DATA step begins to execute.

Super User
Posts: 11,343

Re: Using substr, IN on array elements in MACRO

Posted in reply to chrisengel

If you have many variables in multiple datasets that need similar RECODING then possibly you want a custom INFORMAT.

Please see the example below:

proc format library=work;
invalue YNM (upcase)
'YES','NO'=1
other = 0;
run;

data example;
   input x $;
datalines;
yes
Yes
No
no
maybe
.
never
;
run;

data want;
   set example;
   varx = input(x,YNM.);
run;

Note that if this were my data I would be very tempted to read the values initially with the appropriate informat instead recoding them later.

 

Informats and Formats can sometimes remove a lot of IF/THEN/ELSE code involving non-overlapping values for single variables.

Also note the inclusion of "never" in the data example. Your code using substr would set this to 1 but the original value was not "no".

☑ This topic is solved.

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

Discussion stats
  • 3 replies
  • 427 views
  • 1 like
  • 4 in conversation