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

I have been trying to work on this code (SAS 9.4) and I am not sure where I am messing up. I know that I need to use an array-do loop but I am unsure if it needs to be a nested array-do loop. My goal is to search through all 8 food codes (i.e., Variable Name: OAT_1, OAT_2, OAT_3, etc.).  A person should be considered a case if they have at least two food codes that fall into the following ranges 900-1059 (excluding 1005-1009, 1010-1024, and 1030-1039). Also, I am only taking the first three numbers of each value in the dataset and I need to use the substring function. This is what I have so far:

 

DATA <>

SET <>

ARRAY Case(8)$ OAT_1-OAT_8;

CASE = 0;

DO i = 1 to 8;

IF 900 <= SUBSTR (Case(i), 1, 3) <= 1005 THEN CASE = 1;

IF 1025 <= SUBSTR (Case(i), 1, 3) <= 1029 THEN CASE = 1;

IF 1040 <= SUBSTR (Case(i), 1, 3) <= 1059 THEN CASE = 1;

     Do j = 1 to 8;

     IF 900 <= SUBSTR (Case(j), 1, 3) <= 1005 THEN CASE = 1;

     IF 1025 <= SUBSTR (Case(j), 1, 3) <= 1029 THEN CASE = 1;

     IF 1040 <= SUBSTR (Case(j), 1, 3) <= 1059 THEN CASE = 1;

     END;

END;

RUN;

 

Each time I submit this code, I see observations that should be coded as a non-case coded as a '1' (i.e., case). I have also tried to make the IF/THEN statement under the DO j = 1 to 8 have CASE = 2, but it is still incorrectly coded. 

1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

You can use the : modifier on the comparison operators the test only up the shorter length.

Note that the first two exclusion ranges are contiguous and so can be collapsed into one test.

DATA want;
  SET have;
  ARRAY OAT OAT_1-OAT_8;
  count=0;
  DO i = 1 to dim(oat) ;
    IF  '700' <=: OAT[i] <=:'859' and not 
      ('805' <=: OAT[i]  <=:'824'  or '830' <=: OAT[i] <=:'839' )
      then count= count+1
    ;
  EMD;
  CASE = (count> 1);
run;

If there are values that are less than '10000' then it matters whether or not the values in the OAT_: variables have leading zeros or not.  A value like 075 is not between between 700 and 859, but a value like 75 is.  If that is the case you might want to first convert all of the OAT_: values to have 5 digits by adding this line before the IF statement to convert the string to a number and back to a five digit string with leading zeros.

OAT[i] = put(input(OAT[i],32.),Z5.);

Note that will only work if the values only contain digits because values like '750A' cannot be converted to a number.

 

View solution in original post

4 REPLIES 4
Tom
Super User Tom
Super User

As to the logic:  You need to count.  So set the counter to zero before the loop. Increment when you get a hit. Then check if the count is larger than one after the loop.

 

To get a solution please post example input and expect output.  Your current code has a number of issues.

 

Are your variables numeric or character?  You seem to have assumed they are character because you added the $ in the ARRAY statement. Note if the variables already exist you don't need the $ (you cannot change the type once they are defined). Nor do you need to tell the array statement how many elements are in the array when you have listed them, it can count.

 

You cannot have two variables with the same name.  You are using the name CASE for your array so you need another variable for your counting of matches.

 

SUBSTR() is a for character values and you are comparing the value to numbers. And numbers with 4 digits.  

 

If your variables are digit strings what do they have when the digit string represents a number less than 1,000?  Do the digit strings have leading zeros?

 

JB15
Calcite | Level 5

Sorry, I messed up the ranges. They are actually supposed to fall into the following ranges: 700-859 (excluding 805-809, 810-824, and 830-839). The observations in each variable are have some numbers after it (e.g., 74680) but I only want to focus on the first three digits (i.e., 746) and thought that I needed the substring. Also the variable is considered to be a character variable in SAS.  

 

Essentially, I am trying to find at least two codes (searching OAT_1 through OAT_8) that fall into the ranges to be classified as a 'case.' If 0 or 1 codes fall into the ranges, then I do not want to be classified as a 'case.' I am trying to make the output look like this:

 

1. If I had an observation in OAT_1 that was 747 and another observation in OAT_3 that was 810 (meaning that the observations in OAT_2, OAT_4, OAT_5, OAT_6, OAT_7, and OAT_8 were out of range/do not satisfy the criteria, then I want it to be coded as CASE = 0 because I want at least two codes to fall into the specified ranges. 

 

2. If I had observations in OAT_1 that was 747, OAT_4 that was 795, OAT_6 that was 855 (meaning that OAT_2, OAT_3, OAT_5, OAT_7, and OAT_8 were out of range/do not satisfy the criteria, then I want it to be coded as CASE = 1 because I want at least two codes to fall into the specified ranges. 

 

 

 

Tom
Super User Tom
Super User

You can use the : modifier on the comparison operators the test only up the shorter length.

Note that the first two exclusion ranges are contiguous and so can be collapsed into one test.

DATA want;
  SET have;
  ARRAY OAT OAT_1-OAT_8;
  count=0;
  DO i = 1 to dim(oat) ;
    IF  '700' <=: OAT[i] <=:'859' and not 
      ('805' <=: OAT[i]  <=:'824'  or '830' <=: OAT[i] <=:'839' )
      then count= count+1
    ;
  EMD;
  CASE = (count> 1);
run;

If there are values that are less than '10000' then it matters whether or not the values in the OAT_: variables have leading zeros or not.  A value like 075 is not between between 700 and 859, but a value like 75 is.  If that is the case you might want to first convert all of the OAT_: values to have 5 digits by adding this line before the IF statement to convert the string to a number and back to a five digit string with leading zeros.

OAT[i] = put(input(OAT[i],32.),Z5.);

Note that will only work if the values only contain digits because values like '750A' cannot be converted to a number.

 

JB15
Calcite | Level 5

It works! Thanks so much for your help. 

hackathon24-white-horiz.png

2025 SAS Hackathon: There is still time!

Good news: We've extended SAS Hackathon registration until Sept. 12, so you still have time to be part of our biggest event yet – our five-year anniversary!

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 4 replies
  • 1343 views
  • 0 likes
  • 2 in conversation