BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
mike5
Calcite | Level 5

Hi,

I've been struggling with a do loop in SAS and would be grateful for any assistance. This is the data I have:

data have;

input Parameter $ COL1 $ COL2 $;

  cards;

Intercept AGE DRINKPATTERN

DRINKPATTERN AGE DRINKPATTERN

DRINKPATTERN AGE DRINKPATTERN

DRINKPATTERN AGE DRINKPATTERN

DRINKPATTERN AGE DRINKPATTERN

FISHLASTWEEK AGE DRINKPATTERN

AGE AGE DRINKPATTERN AGE DRINKPATTERN

AGE AGE DRINKPATTERN AGE DRINKPATTERN

AGE AGE DRINKPATTERN AGE DRINKPATTERN

FISHLASTWEEK*AGE AGE DRINKPATTERN

FISHLASTWEEK*AGE AGE DRINKPATTERN

FISHLASTWEEK*AGE AGE DRINKPATTERN

;

run;

I want to assess whether the string values contained in the variables COL1 or COL2 are evident in the field Parameter and if so assign a value of 2 to the variable TYPE.

The macro I created is below. The problem I am having is that the if statement does not seem to generate and the mprint option highlights this. Any assistance

is greatly appreaciated,

thanks,

%macro ClassIdentifier(value);

data want;

set have;

TYPE = 1;

   %do i=1 %to &Value;

   %let Varname = COL&i;

      %if %index(Parameter, &Varname ) NE 0 %then TYPE = 2;

      run;

   %end;

%mend;

options mprint;

%ClassIdentifier(2)

1 ACCEPTED SOLUTION

Accepted Solutions
user24feb
Barite | Level 11

An alternative;

%macro ClassIdentifier(value);
data want (Drop=i);
set have;
Type=1;
Array C{*} $30. COL:;
Do i=1 To Dim(C);
  If Index(Parameter,C{i}) Then Type=2;
  Else Type=Min(Type,2);
End;
Run;
%mend;
%ClassIdentifier(value=2)

View solution in original post

8 REPLIES 8
RW9
Diamond | Level 26 RW9
Diamond | Level 26

Why do you need a macro?  You could just create a flag in you read:

data have;

input Parameter $ COL1 $ COL2 $;

flag1=index(parameter,col1);  /* Flag for first one */

flag2=index(parameter,col2);   /* Flag for second */

  cards;

Intercept AGE DRINKPATTERN

DRINKPATTERN AGE DRINKPATTERN

DRINKPATTERN AGE DRINKPATTERN

DRINKPATTERN AGE DRINKPATTERN

DRINKPATTERN AGE DRINKPATTERN

FISHLASTWEEK AGE DRINKPATTERN

AGE AGE DRINKPATTERN AGE DRINKPATTERN

AGE AGE DRINKPATTERN AGE DRINKPATTERN

AGE AGE DRINKPATTERN AGE DRINKPATTERN

FISHLASTWEEK*AGE AGE DRINKPATTERN

FISHLASTWEEK*AGE AGE DRINKPATTERN

FISHLASTWEEK*AGE AGE DRINKPATTERN

;

run;

mike5
Calcite | Level 5

Hi, thanks for the responses. I need a loop, (maybe not a macro) as there will be multiple fields all with COL at the beginning.

data have;

input Parameter $ COL1 $ COL2 $;

  cards;

Intercept AGE DRINKPATTERN

DRINKPATTERN AGE DRINKPATTERN

DRINKPATTERN AGE DRINKPATTERN

DRINKPATTERN AGE DRINKPATTERN

DRINKPATTERN AGE DRINKPATTERN

FISHLASTWEEK AGE DRINKPATTERN

AGE AGE DRINKPATTERN

AGE AGE DRINKPATTERN

AGE AGE DRINKPATTERN

FISHLASTWEEK*AGE AGE DRINKPATTERN

FISHLASTWEEK*AGE AGE DRINKPATTERN

FISHLASTWEEK*AGE AGE DRINKPATTERN

;

run;

Using the data above, I can create  a new field using a data step with the following:

data want;

set have;

Type = 1;

if index(Parameter, col1 ) NE 0 then Type = 2;

run;

I would like this to run in a loop and replace the col1 with col2 etc

the output should have an additional field TYPE that has a value of 2 if the strings in col1 or col2 are found in the field parameter:

Parameter                    Col1     Col2                    Type

Intercept                   AGE      DRINKPATTERN     1

DRINKPATTERN     AGE      DRINKPATTERN     2

DRINKPATTERN     AGE      DRINKPATTERN     2

DRINKPATTERN     AGE      DRINKPATTERN     2

DRINKPATTERN     AGE      DRINKPATTERN     2

FISHLASTWEEK      AGE      DRINKPATTERN     1

AGE                         AGE      DRINKPATTERN     2

apologies for omissions previously, I will try the macro with the array, thank you

mike5
Calcite | Level 5

Hi,

thanks for the responses. I used the array and it works great, thank you. I'm still a bit miffed about the IF statement not functioning in the loop however ... maybe for another day!

Regards,

Michael

pwe
Fluorite | Level 6 pwe
Fluorite | Level 6

" I'm still a bit miffed about the IF statement not functioning in the loop however "

are you referring to the line:   

     %if %index(Parameter, &Varname ) NE 0 %then TYPE = 2;

or the line:

     If   index(Parameter, col1 ) NE 0 then Type = 2;

mike5
Calcite | Level 5

Hi, the line:

%if %index(Parameter, &Varname ) NE 0 %then TYPE = 2;

I managed to get a little help with this and found it was an easy fix, just remove the % symbols as:

if index(Parameter, &Varname ) NE 0 then TYPE = 2;

Works great now. I also implemented the array version as an alternative.

thanks for the response

pwe
Fluorite | Level 6 pwe
Fluorite | Level 6

Yes, the line 

%if %index(Parameter, &Varname ) NE 0 %then TYPE = 2;

was working correctly, your expectations were wrong Smiley Happy

You were using macro statements where you should have used data step statements. A common problem when trying to learn and apply macro.

ballardw
Super User

It will help if you provide an example of what you expect for output.

Did you create a basic data step that provided the desired output before attempting the macro approach? If so, please post that.

If you want to see if the variable Parameter in have contains the text COL1 you want:

  if   index(Parameter,"COL&I") , no need to create the additional macro variable. You are getting false for the result as the string

Parameter does not contain COL1 or COL2. The macro processor not the data step evaluates the %index function and %if / %then.

Also, the index function is case sensitive so you may want index (upcase(Parameter),"COL&I").

%do I=1 to &value;

      if   index(Parameter,"COL&I")  ne 0 then type=2;

%end;

run;

The if loop should then generate:

if index(Parameter,"COL1") ne 0 then type=2;

if index(Parameter,"COL2") ne 0 then type=2;

Also having the %do %end enclose the Run statement you could be generating at least one Run without a data step associated.

user24feb
Barite | Level 11

An alternative;

%macro ClassIdentifier(value);
data want (Drop=i);
set have;
Type=1;
Array C{*} $30. COL:;
Do i=1 To Dim(C);
  If Index(Parameter,C{i}) Then Type=2;
  Else Type=Min(Type,2);
End;
Run;
%mend;
%ClassIdentifier(value=2)

sas-innovate-2024.png

Don't miss out on SAS Innovate - Register now for the FREE Livestream!

Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.

 

Register now!

How to Concatenate Values

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 8 replies
  • 2398 views
  • 3 likes
  • 5 in conversation