Hi,
Ok, back to arrays. This code seems to work for me, and generates no errors, but instead of having the data from datalines display as Benzene, I am getting 0 observations for Benzene. Any reasons why?
Libname Review'/folders/myfolders/Review' ; Libname Learn'/folders/myfolders/Learn' ; Libname myformat'/folders/myfolders/sasuser.v94' ; Options fmtsearch=(myformat) ; /*Creating a Multidimensional Array*/ Data Review.Benzene_Levels ; Array Level{1944:1949,5} _temporary_; /*populates two dimensional array*/ If _n_ = 1 then Do year = 1944 to 1949 ; Do Job = 1 to 5 ; Input Level(Year,Job) @ ; End ; End ; Set learn.expose ; Job = Input(Translate(Jobcode,'12345', 'ABCDE'), 1.) ; /*translates Jobcode to Job*/ Benzene = Level{Year,Job} ; /*Defines Benzene variable at a confluence of Year and Job*/ Drop Job ; Datalines ; 220 180 210 110 90 202 170 208 100 85 150 110 150 60 50 105 56 88 40 20 10 45 22 22 10 8 ; Proc print data=Review.Benzene_Levels noobs ; run ;
Try this:
Datalines ; 220 180 210 110 90 202 170 208 100 85 150 110 150 60 50 105 56 88 40 20 10 45 22 22 10 8 ;
Instead of your current data lines
The trail @ only holds the input line until you run out of data on a single input line. So your array was only populated for the first 5 or 6 elements of the actual 30 your read is requesting.
Remove the _temporary and all of the bits involving the second data set and just see what you were reading. That likely explains the missing result especially if the "year" was latter than 1944. Also you don't have enough values to fill a 6 by 5 array (1944 to 1949 is 6) so you would only have level [1949, 1 ].
Minor suggestion is to keep the {} only in the array definition as well. Better would be to use [ ] for array use so it is easier to identify the usage for array.
I suggest investigating custom informats instead of the translate code. Since translate only works with single digits you would have issues with job codes past J and an informat can be made to force to upper case for conversion if needed.
Something like:
proc format library=work; invalue jobcode (upcase) 'A'=1 'B'=2 'C'=3 'D'=4 'E'=5 /* optional assign a default for something not in the expected values other= 1 */ ; run;
Which allows:
Job = Input(Jobcode, jobcode.);
And if later you get a jobcode Q that should be item
Hi,
I tried making changes suggested. It should be pointed out that the Set learn.expose only has years between 1944 and 1948. I changed the years in the array to reflect this. Now I am getting an 'array subscription out of range error.
Below, I have included my code, then the data set learn.expose, and finally, the error log. Thanks!
Libname Review'/folders/myfolders/Review' ; Libname Learn'/folders/myfolders/Learn' ; Libname myformat'/folders/myfolders/sasuser.v94' ; Options fmtsearch=(myformat) ; /*Creating a Multidimensional Array*/ Data Review.Benzene_Levels ; Array Level{1945:1948,5} ; /*populates two dimensional array*/ If _n_ = 1 then Do year = 1944 to 1948 ; Do Job = 1 to 5 ; Input Level{Year,Job} @ ; End ; End ; Set learn.expose ; Job = Input(Translate(Jobcode,'12345', 'ABCDE'), 1.) ; /*translates Jobcode to Job*/ Benzene = Level{Year,Job} ; /*Defines Benzene variable at a confluence of Year and Job*/ Drop Job ; Datalines ; 220 180 210 110 90 202 170 208 100 85 150 110 150 60 50 105 56 88 40 20 45 22 22 10 8 ; Proc print data=Review.Benzene_Levels noobs ; run ;
data learn.expose; input Worker $ Year JobCode : $1.; datalines; 001 1944 B 002 1948 E 003 1947 C 005 1945 A 006 1948 D ;
Errors (1) ERROR: Array subscript out of range at line 73 column 7. Warnings (2) Notes (9) 1 OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK; 61 62 Libname Review'/folders/myfolders/Review' ; NOTE: Libref REVIEW was successfully assigned as follows: Engine: V9 Physical Name: /folders/myfolders/Review 63 Libname Learn'/folders/myfolders/Learn' ; NOTE: Libref LEARN refers to the same physical library as LEARN2. NOTE: Libref LEARN was successfully assigned as follows: Engine: V9 Physical Name: /folders/myfolders/Learn 64 Libname myformat'/folders/myfolders/sasuser.v94' ; NOTE: Libref MYFORMAT refers to the same physical library as SASUSER. NOTE: Libref MYFORMAT was successfully assigned as follows: Engine: V9 Physical Name: /folders/myfolders/sasuser.v94 65 Options fmtsearch=(myformat) ; 66 67 /*Creating a Multidimensional Array*/ 68 Data Review.Benzene_Levels ; 69 Array Level{1945:1948,5} ; /*populates two dimensional array*/ 70 If _n_ = 1 then 71 Do year = 1944 to 1948 ; 72 Do Job = 1 to 5 ; 73 Input Level{Year,Job} @ ; 74 End ; 75 End ; 76 Set learn.expose ; 77 Job = Input(Translate(Jobcode,'12345', 'ABCDE'), 1.) ; /*translates Jobcode to Job*/ 78 Benzene = Level{Year,Job} ; /*Defines Benzene variable at a confluence of Year and Job*/ 79 Drop Job ; 80 Datalines ; ERROR: Array subscript out of range at line 73 column 7. RULE: ----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0 81 220 180 210 110 90 Level1=. Level2=. Level3=. Level4=. Level5=. Level6=. Level7=. Level8=. Level9=. Level10=. Level11=. Level12=. Level13=. Level14=. Level15=. Level16=. Level17=. Level18=. Level19=. Level20=. year=1944 Job=1 Worker= JobCode= Benzene=. _ERROR_=1 _N_=1 NOTE: The SAS System stopped processing this step because of errors. WARNING: The data set REVIEW.BENZENE_LEVELS may be incomplete. When this step was stopped there were 0 observations and 24 variables. WARNING: Data set REVIEW.BENZENE_LEVELS was not replaced because this step was stopped. NOTE: DATA statement used (Total process time): real time 0.00 seconds cpu time 0.00 seconds 86 ; 87 88 Proc print data=Review.Benzene_Levels noobs ; 89 run ; NOTE: No observations in data set REVIEW.BENZENE_LEVELS. NOTE: PROCEDURE PRINT used (Total process time): real time 0.00 seconds cpu time 0.00 seconds 90 91 /* Data learn.look_up ; 92 array level{1944:1949,5} _temporary_; 93 if _n_ = 1 then do Year = 1944 to 1949; 94 do Job = 1 to 5; 95 input level{Year,Job} @; 96 end; 97 end; 98 99 set learn.expose; 100 Job = input(translate(Jobcode,'12345','ABCDE'),1.); 101 Benzene = level{Year,Job}; 102 drop Job; 103 datalines; 104 220 180 210 110 90 105 202 170 208 100 85 106 150 110 150 60 50 107 105 56 88 40 30 108 60 30 40 20 10 109 45 22 22 10 8 110 ; 111 112 Proc print data=learn.look_up noobs ; 113 run ; */ 114 115 OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK; 128
Now, two issues need to be addressed:
@FreelanceReinh wrote:
Now, two issues need to be addressed:
- The range of years in the array definition should start with 1944 in order to match the range in the corresponding DO loop. This will solve the subscript-out-of-range issue.
- You should add the keyword _temporary_ again in the array definition. (It was correct in your initial post.) It ensures that the array values are retained across iterations of the data step. Otherwise variable Benzene will receive missing values in all but the first observation. Moreover, the variables Level1-Level25 are probably not needed in Review.Benzene_Levels, so that a temporary array is ideal to handle them. I think, ballardw's suggestion to remove _temporary_ was just for diagnostic purposes (to make those temporary values visible).
Yes, the purpose of removing the _temporary_ was so the OP could see which values were assigned to which variables and that the entire array was not populated. Also as a sort of guideline to show that the "read" must align with the total number of indices to really understand what the array portion of the code is doing.
Hi @ManitobaMoose,
I think the crucial point is that the number of values following the DATALINES statement (26) is less than the number of times the INPUT statement reads from those values (30), as ballardw pointed out already. As a consequence, you should have got a "NOTE: LOST CARD." and "_ERROR_=1" in the log -- in addition to the empty dataset. These log entries don't quite look like the common red error messages, but are nevertheless serious.
Adding four arbitrary (e.g. missing) values to the list of numbers solved the problem at least in my test program.
ballardw's additional suggestions for improvement are worthwhile to consider as well.
Ok. That makes sense.
I rewrote the code a bit. I am no longer getting errors, but I am getting a Note of lost Card. Also, there are 0 observations. Please see the code, and then the log, below. Thanks.
Libname Review'/folders/myfolders/Review' ; Libname Learn'/folders/myfolders/Learn' ; Libname myformat'/folders/myfolders/sasuser.v94' ; Options fmtsearch=(myformat) ; /*Creating a Multidimensional Array*/ Proc format Library=Myformat ; Invalue LettertoNum 'A' = 1 'B' = 2 'C' = 3 'D' = 4 'E' = 5 Other = 100 ; run ; Data Review.Benzene_Levels ; Array Level{1944:1949,5} _temporary_ ; /*populates two dimensional array*/ If _n_ = 1 then Do year = 1944 to 1949 ; Do Job = 1 to 5 ; Input Level{Year,Job} ; End ; End ; Set learn.expose ; Job = input(Jobcode, LettertoNum.) ; /*translates Jobcode to Job*/ Benzene = Level{Year,Job} ; /*Defines Benzene variable at a confluence of Year and Job*/ Drop Job ; Datalines ; 220 180 210 110 90 202 170 208 100 85 150 110 150 60 50 105 56 88 40 20 45 22 22 10 8 ; Proc print data=Review.Benzene_Levels noobs ; run ;
Log Below
SAS® Studio Folder Shortcuts My Folders Errors Warnings Notes (13) NOTE: Libref REVIEW was successfully assigned as follows: NOTE: Libref LEARN refers to the same physical library as LEARN2. NOTE: Libref LEARN was successfully assigned as follows: NOTE: Libref MYFORMAT refers to the same physical library as SASUSER. NOTE: Libref MYFORMAT was successfully assigned as follows: NOTE: Informat LETTERTONUM is already on the library MYFORMAT.FORMATS. NOTE: Informat LETTERTONUM has been output. NOTE: PROCEDURE FORMAT used (Total process time): NOTE: LOST CARD. NOTE: The data set REVIEW.BENZENE_LEVELS has 0 observations and 4 variables. NOTE: DATA statement used (Total process time): NOTE: No observations in data set REVIEW.BENZENE_LEVELS. NOTE: PROCEDURE PRINT used (Total process time): 1 OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK; 61 62 Libname Review'/folders/myfolders/Review' ; NOTE: Libref REVIEW was successfully assigned as follows: Engine: V9 Physical Name: /folders/myfolders/Review 63 Libname Learn'/folders/myfolders/Learn' ; NOTE: Libref LEARN refers to the same physical library as LEARN2. NOTE: Libref LEARN was successfully assigned as follows: Engine: V9 Physical Name: /folders/myfolders/Learn 64 Libname myformat'/folders/myfolders/sasuser.v94' ; NOTE: Libref MYFORMAT refers to the same physical library as SASUSER. NOTE: Libref MYFORMAT was successfully assigned as follows: Engine: V9 Physical Name: /folders/myfolders/sasuser.v94 65 Options fmtsearch=(myformat) ; 66 67 /*Creating a Multidimensional Array*/ 68 69 Proc format Library=Myformat ; 70 70 ! Invalue LettertoNum 71 'A' = 1 72 'B' = 2 73 'C' = 3 74 'D' = 4 75 'E' = 5 76 Other = 100 ; NOTE: Informat LETTERTONUM is already on the library MYFORMAT.FORMATS. NOTE: Informat LETTERTONUM has been output. 77 run ; NOTE: PROCEDURE FORMAT used (Total process time): real time 0.01 seconds cpu time 0.01 seconds 78 79 Data Review.Benzene_Levels ; 80 Array Level{1944:1949,5} _temporary_ ; /*populates two dimensional array*/ 81 If _n_ = 1 then 82 Do year = 1944 to 1949 ; 83 Do Job = 1 to 5 ; 84 Input Level{Year,Job} ; 85 End ; 86 End ; 87 Set learn.expose ; 88 Job = input(Jobcode, LettertoNum.) ; /*translates Jobcode to Job*/ 89 Benzene = Level{Year,Job} ; /*Defines Benzene variable at a confluence of Year and Job*/ 90 Drop Job ; 91 Datalines ; NOTE: LOST CARD. RULE: ----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0 97 ; year=1945 Job=1 Worker= JobCode= Benzene=. _ERROR_=1 _N_=1 NOTE: The data set REVIEW.BENZENE_LEVELS has 0 observations and 4 variables. NOTE: DATA statement used (Total process time): real time 0.01 seconds cpu time 0.01 seconds 97 ; 98 99 Proc print data=Review.Benzene_Levels noobs ; 100 run ; NOTE: No observations in data set REVIEW.BENZENE_LEVELS. NOTE: PROCEDURE PRINT used (Total process time): real time 0.00 seconds cpu time 0.01 seconds 101 102 /* Data learn.look_up ; 103 array level{1944:1949,5} _temporary_; 104 if _n_ = 1 then do Year = 1944 to 1949; 105 do Job = 1 to 5; 106 input level{Year,Job} @; 107 end; 108 end; 109 110 set learn.expose; 111 Job = input(translate(Jobcode,'12345','ABCDE'),1.); 112 Benzene = level{Year,Job}; 113 drop Job; 114 datalines; 115 220 180 210 110 90 116 202 170 208 100 85 117 150 110 150 60 50 118 105 56 88 40 30 119 60 30 40 20 10 120 45 22 22 10 8 121 ; 122 123 Proc print data=learn.look_up noobs ; 124 run ; */ 125 126 OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK;
Now, two other issues need to be resolved:
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
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.