BookmarkSubscribeRSS Feed
ManitobaMoose
Quartz | Level 8

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 ; 
7 REPLIES 7
ballardw
Super User

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

ManitobaMoose
Quartz | Level 8

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        
FreelanceReinh
Jade | Level 19

Now, two issues need to be addressed:

 

  1. 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.
  2. 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).

 

ballardw
Super User

@FreelanceReinh wrote:

Now, two issues need to be addressed:

 

  1. 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.
  2. 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.

FreelanceReinh
Jade | Level 19

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.

ManitobaMoose
Quartz | Level 8

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;
FreelanceReinh
Jade | Level 19

Now, two other issues need to be resolved:

 

  1. The range of years in array definition and DO loop should end with 1948, since "learn.expose only has years between 1944 and 1948" (as you wrote earlier). Or, you need 30 "Level" values rather than only 25. (The note "LOST CARD" indicates that there are fewer values than INPUT is trying to read.)
  2. You should add the trailing @-sign to the INPUT statement (as you did initially). This is necessary in order to read more than one "Level" value from each row after the DATALINES statement.

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
  • 7 replies
  • 935 views
  • 0 likes
  • 3 in conversation