user190080
user190080

Reputation: 535

Mixing macro-DO-loops with data step DO-loops

Some context:

I have a string of digits (not ordered, but with known range 1 - 78) and I want to extract the digits to create specific variables with it, so I have

"64,2,3" => var_64 = 1; var_02 = 2; var_03 = 1; (the rest, like var_01 are all set to missing)

I basically came up with two solutions, one is using a macro DO loop and the other one a data step DO loop. The non-macro solution was to fist initialize all variables var_01 - var_78 (via a macro), then to put them into an array and then to gradually set the values of this array while looping through the string, word-by-word.

I then realized that it would be way easier to use the loop iterator as a macro variable and I came up with this MWE:

%macro fast(w,l);
do p = 1 to &l.;
    %do j = 1 %to 9;
        if &j. =  scan(&w.,p,",") then var_0&j. = 1 ;
    %end;
    %do j = 10 %to 78;
        if &j. =  scan(&w.,p,",") then var_&j. = 1 ;
    %end;
end;
%mend;

data want;
string = "2,4,64,54,1,4,7";
l = countw(string,",");
%fast(string,l);
run; 

It works (no errors, no warnings, expected result) but I am unsure about mixing macro-DO-loops and non-macro-DO-loops. Could this lead to any inconsistencies or should I just stay with the non-macro solution?

Upvotes: 1

Views: 545

Answers (1)

Tom
Tom

Reputation: 51566

Your current code is comparing numbers like 1 to strings like "1".

&j. =  scan(&w.,p,",")

It will work as long as the strings can be converted into numbers, but it is not a good practice. It would be better to explicitly convert the strings into numbers.

input(scan(&w.,p,","),32.)

You can do what you want with an array. Use the number generated from the next item in the list as the index into the array.

data want;
  string = "2,4,64,54,1,4,7";
  array var_ var_01-var_78 ;
  do index=1 to countw(string,",");
     var_[input(scan(string,index,","),32.)]=1;
  end;
  drop index;
run;

Upvotes: 2

Related Questions