BookmarkSubscribeRSS Feed
trevand
Obsidian | Level 7

If I use the last suggestion I would have to spell out 20 times or so the different indicators that I want to create. That's why I wanted to use the var_list macro.

 

Can you please explain why

do j=1 to countw('&&&var..', ',');

will only iterate until the first string? In the example that you provided B3 is still found if use the code above.

 

Tom
Super User Tom
Super User

Try it yourself and see.

 1          data _null_;
 2            do j=1 to countw('&&&var..', ',');
 3              put j=1;
 4            end;
 5          run;
 
 j=1
 NOTE: DATA statement used (Total process time):
       real time           0.00 seconds
       cpu time            0.00 seconds

Try this to see WHY.

 1          data _null_;
 2            string = '&&&var..';
 3            put string=;
 4          run;
 
 string=&&&var..
 NOTE: DATA statement used (Total process time):
       real time           0.00 seconds
       cpu time            0.00 seconds

The macro processor IGNORES strings made using single quote characters instead of double quote characters.

 

You have to type the same information either way.

Better to have the lists in data 

data dxgroups;
  infile datalines truncover;
  length varname $32 num 8 code $10 disease $50;
  input varname  disease $50. ;
  do codenum=1 by 1 until(missing(code));
     input code @ ;
     if not missing(code) then output;
  end;
cards;
hpb Hypertension
A1 A2 A3 A4
db Diabetes
B1 B2 B3
;

and use the data to generate the code.

For example you could use it to generate calls to %DXTEST() macro I showed.

filename code temp;
data _null_;
  file code;
  set dxgroups;
  by varname notsorted;
  if first.varname then put '%dxtest(' varname ',' @;
  put code :$quote. @;
  if last.varname then put ')';
run;

And then you can use %INCLUDE to execute that generated code where you want.

data want;
  set have;
  array var_[20] ;
%include code / source2;
  drop i;
run;
trevand
Obsidian | Level 7

But this should be okay then?

 

%let testA=("A1" "A2" "A3");
%let testB=("B1" "B2" "B3");


data NEED;
set HAVE;

array cond_testA {20} VAR_1-VAR_20;
do i=1 to dim (cond_testA);
do j=1 to countw('&testA.', ',');
if (cond_testA {i} in &testA.) then do;
testA=1;
end;
end;
end;

array cond_testB {20} VAR_1-VAR_20;
do i=1 to dim (cond_testB);
do j=1 to countw('&testB.', ',');
if (cond_testB {i} in &testB.) then do;
testB=1;
end;
end;
end;


run;

The problem only arises with &&&var..? Sorry I'm still confused. I'm coming from stata where it's super easy to loop through strings.

 

Tom
Super User Tom
Super User

There is a huge difference to SAS macro processor between

do j=1 to countw('&testB.', ',');

and

do j=1 to countw("&testB.", ',');

And even if you changed to the second then SAS code that the macro processor would pass onto SAS to execute would look like:

do j=1 to countw("("B1" "B2" "B3")", ',');
if (cond_testB {i} in ("B1" "B2" "B3")) then do;
testB=1;
end;

Which not only is invalid syntax it does not make any sense.

 

Did you mean to do something like this?

testB=0;
do i=1 to dim(cond_testB);
  if (cond_testB[i] in &testB.) then testB=1;
end;

If so then that is what the DO loops I showed are doing,

do i=1 to dim(cond_testB) until(testB);
  testB= (cond_testB[i] in &testB.) ;
end;

but they stop looping as soon as there is a match.

 

So your code worked because the two mistakes (miss use of macro code and the extra unneeded DO loop) cancel each other out.

 

 

Note also that [ and ] are easier to type and easier to distinguish from ( and ) in the code than { and }.

 

 

trevand
Obsidian | Level 7
data have;
  row+1;
  input (var_1-var_4) ($);
cards;
A1 C1 .  .
D1 C2 B3 .
. . . .
;

data want;
  set have;
  array var_[4];
  do i=1 to dim(var_) until(testA);
    testA = var_[i] in ('A1' 'A2' 'A3');
  end;
  do i=1 to dim(var_) until(testB);
    testB = var_[i] in ('B1' 'B2' 'B3');
  end;
  drop i;
run;

I will just use this code as you suggested. One question though. Why do you need until(testA)?

Tom
Super User Tom
Super User

@trevand wrote:

...

Why do you need until(testA)?

So it does not have to keep hunting after it already found the result.

Also if you don't stop when it finds a match you have to add extra code to prevent the later comparisons from overwriting the earlier positive  result.  And something to set the negatives results to zero instead of missing.

trevand
Obsidian | Level 7

Great, thanks! I think I'm understanding it now. I will use the following code that you proposed and add %let for the codelists:

 

data have;
  row+1;
  input (var_1-var_4) ($);
cards;
A1 C1 .  .
D1 C2 B3 .
. . . .
;

%let codesetA=('A1' 'A2' 'A3')
%let codesetB=('B1' 'B2' 'B3')
data want; set have; array var_[4]; do i=1 to dim(var_) until(testA); testA = var_[i] in &codesetA. ; end; do i=1 to dim(var_) until(testB); testB = var_[i] in &codesetB.; end; drop i; run;

The code set though could have either "" or '', right? In other words

 

%let codesetA=('A1' 'A2' 'A3')

would be the same as

%let codesetA=("A1" "A2" "A3")
Tom
Super User Tom
Super User

Yes.  The regular SAS language does not care which character you use to make a string literal.  It is just the macro processor that cares.  The reason is so you can have a string with & or % characters in them that are NOT meant to be processed by the macro processor.

If you try to set company name to AT&T and you use double quotes then the macro processor will look for the value of the macro variable named T.  So use single quotes instead.

company_name='AT&T';
trevand
Obsidian | Level 7
@Tom thanks for all the explanations!

hackathon24-white-horiz.png

The 2025 SAS Hackathon has begun!

It's finally time to hack! Remember to visit the SAS Hacker's Hub regularly for news and updates.

Latest Updates

Mastering the WHERE Clause in PROC SQL

SAS' Charu Shankar shares her PROC SQL expertise by showing you how to master the WHERE clause using real winter weather data.

Find more tutorials on the SAS Users YouTube channel.

Discussion stats
  • 23 replies
  • 5898 views
  • 3 likes
  • 5 in conversation