Consider this:
%macro t / minoperator;
%if 1=1 %then %put a;
%if 1 in 1 2 %then %put b;
%if 1=1 & 2=2 %then %put c;
%if 1 in 1 2 & 2=2 %then %put d;
%if 1 in 1 2 & 2>2 %then %put e;
%if 1 in 1 2 and 2>2 %then %put f;
%mend;
%t
The output is:
a
b
c
d
e
e should not be here right?
The IN operator discounts and as a keyword, but counts & as a string in the list.
Now I know, and you too if you didn't already.
/*
Chris ,
You are right .
It seems that '&' is a value for IN operator
You need '()' to tell SAS the range of operator.
That also tells us it always righ to use '()'
to define range of operator.
Like this :
*/
%macro t / minoperator mindelimiter=' ' ;
%if 1=1 %then %put a;
%if 1 in 1 2 %then %put b;
%if 1=1 & 2=2 %then %put c;
%if 1 in 1 2 & 2=2 %then %put d;
%if (1 in 1 2) & (2>2) %then %put e;
%if 1 in 1 2 and 2>2 %then %put f;
%mend;
%t
79 /* 80 Chris , 81 You are right . 82 It seems that '&' is a value for IN operator 83 You need '()' to tell SAS the range of operator. 84 That also tells us it always righ to use '()' 85 to define range of operator. 86 Like this : 87 */ 88 89 %macro t / minoperator mindelimiter=' ' ; 90 %if 1=1 %then %put a; 91 %if 1 in 1 2 %then %put b; 92 %if 1=1 & 2=2 %then %put c; 93 %if 1 in 1 2 & 2=2 %then %put d; 94 %if (1 in 1 2) & (2>2) %then %put e; 95 %if 1 in 1 2 and 2>2 %then %put f; 96 %mend; 97 %t a b c d
@ChrisNZ Interesting. Thank you 🙂
You could also just add the parentheses around the list of values.
%if 1 in (1 2) & 2>2 %then %put e;
It never made sense to me why you would do that since the IN operator in macro code does not require it, unlike in regular SAS code. But it does help let the parser know where the list starts and ends.
I didn't know, and think maybe it's worth submitting as a bug.
Honestly, there were so many problems in implementing the macro IN operator in the beginning, I've stayed away from it.
I agree with your diagnosis: if you don't put parentheses around the argument, the IN operator will treat & and also | as strings, but will treat AND and OR as operators that end the argument. Another test case:
%macro t / minoperator;
%put 1 in 0 & 1 evaluates to: %eval(1 in 0 & 1) ; *Returns 1 but should return 0 ;
%put 1 in 0 and 1 evaluates to: %eval(1 in 0 and 1) ; *Returns 0 ;
%put 0 in 1 | 0 evaluates to: %eval(0 in 1 | 0) ; *Returns 1 but should return 0 ;
%put 0 in 1 or 0 evaluates to: %eval(0 in 1 or 0) ; *Returns 0 ;
%mend;
%t
It looks to me like the AND is capable of ending the list of arguments to the IN operator. Below reasonably errors, because SAS can't evaluate the expression 0 1:
%macro t / minoperator;
%put %eval(1 in 0 and 0 1 ) ; *errors, sensibly ;
%mend;
%t
But the below executes, and the only way that happens is if the & operator was sucked into the list of arguments for IN:
%macro t / minoperator;
%put %eval(1 in 0 & 0 1 ) ; *returns 1 ;
%mend;
%t
@Ksharp Yes
%if (1 in 1 2) & (2>2) %then %put e;
is the cleanest imho
@Tom Good point, though I don't think I'll use the syntax
%if 1 in (1 2) & 2>2 %then %put e;
The parentheses look like they are part of the string values to test. This is confusing to me.
@PeterClemmensen Thank you!
@Quentin Good set of additional tests, thank you!
It's finally time to hack! Remember to visit the SAS Hacker's Hub regularly for news and updates.
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.
Ready to level-up your skills? Choose your own adventure.