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

Hi,

 

Back to this. Two Dimensional Arrays. Can someone see why the first program works without errors and the second does not. They seem equivalent to me.

 

First program:

 

data learn.look_up;
   /******************************************************
      Create the array, the first index is the year and
      it ranges from 1944 to 1949. The second index is
      the job code (we're using 1-5 to represent job codes
      A through E).
   *******************************************************/
   array level{1944:1949,5} _temporary_;
   /* Populate the array */
   if _n_ = 1 then do Year = 1944 to 1949;
      do Job = 1 to 5;
         input level{Year,Job} @; 
      end;
   end;

   set learn.expose;
   /* Compute the job code index from the JobCode value */
   Job = input(translate(Jobcode,'12345','ABCDE'),1.);
   Benzene = level{Year,Job};
   drop Job;
datalines;
220 180 210 110 90
202 170 208 100 85
150 110 150 60 50
105 56 88 40 30
60 30 40 20 10
45 22 22 10 8
;

Proc print data=learn.look_up noobs ; 
run ;

 

First Program Results.

 

Year 	Worker 	JobCode 	Benzene
1944 	001 	B 	180
1948 	002 	E 	10
1947 	003 	C 	88
1945 	005 	A 	202
1948 	006 	D 	20

 

 

 

Second Program

 

 

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;
   /* Compute the job code index from the JobCode value */
   Job = input(translate(Jobcode,'12345','ABCDE'),1.);
   Benzene = level{Year,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 ;

Second Program Log

 

 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.00 seconds
       cpu time            0.00 seconds
       
 
 78         
 79         Data Review.Benzene_Levels ;
 80         Array Level{1944:1949,5} _temporary_ ; /*populates two dimensional array*/
 81            if _n_ = 1 then do Year = 1944 to 1949;
 82               do Job = 1 to 5;
 83                  input level{Year,Job} @;
 84               end;
 85            end;
 86            set learn.expose;
 87            /* Compute the job code index from the JobCode value */
 88            Job = input(translate(Jobcode,'12345','ABCDE'),1.);
 89            Benzene = level{Year,Job};
 90            drop Job;
 91         Datalines ;
 
 NOTE: LOST CARD.
 RULE:      ----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0                     
 97         ;
 Year=1949 Job=1 Worker=  JobCode=  Benzene=. _ERROR_=1 _N_=1
 NOTE: SAS went to a new line when INPUT statement reached past the end of a line.
 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.00 seconds
       

 

Below is the code for the set learn.expose.

 

 

 

data learn.expose;
   input Worker $ Year JobCode : $1.;
datalines;
 001      1944     B
 002      1948     E
 003      1947     C
 005      1945     A
 006      1948     D
 ;

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
novinosrin
Tourmaline | Level 20

Notes:

  1. Array statement complies a multidimensional array with 6 rows (1944:1949) being the range and times 5 makes it 30 columns -> 6*5
  2. On your first iteration when _n_=1, your input statement starts reading raw data from datalines or an external file if specified in a infile statement
  3. When point 2 _n_=1 becomes true, the nested loop iterates 6*5=30 times meaning 5 times for each year populating each element of the array one by one
  4. Temporary array retains values across of observations until sas processes each and every record
  5. Your set statement reads data from your input dataset expose and that’s where values of jobcode are referred from, using which new variable job is created with an assignment statement

I deeply apologize for the infile datalines truncover. This shouldn’t be used as you need the input statement to read the next line by default. Like @Astounding pointed out, you actually need another datalines to read and populate array for the dimension year(1949,1……5)

However since you have only 5 datalines, sas can’t find or read the line to populate for the year 1949.

So the correction is do year=1944 to 1948; instead of 1949

And now run and examine the corrected version below:

Data Benzene_Levels ; 

	Array Level{1944:1948,5}   ; /*populates two dimensional array*/
	retain level;
   if _n_ = 1 then do Year = 1944 to 1948;

      do Job = 1 to 5;
         input level{Year,Job} @ ; 
      end;
   end;
   set expose;
   /* Compute the job code index from the JobCode value */
   Job = input(translate(Jobcode,'12345','ABCDE'),1.);
   Benzene = level{Year,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
;

View solution in original post

8 REPLIES 8
Astounding
PROC Star

Aren't you missing a line of data in the second DATA step?

novinosrin
Tourmaline | Level 20
data expose;
   input Worker $ Year JobCode : $1.;
datalines;
 001      1944     B
 002      1948     E
 003      1947     C
 005      1945     A
 006      1948     D
 ;
Data Benzene_Levels ; 
infile datalines truncover;
	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 expose;
   /* Compute the job code index from the JobCode value */
   Job = input(translate(Jobcode,'12345','ABCDE'),1.);
   Benzene = level{Year,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
;
ManitobaMoose
Quartz | Level 8

Ok, but isn't that data from expose already referenced by the code set learn.expose?

novinosrin
Tourmaline | Level 20

Yes i just ran a test in my local. That's about it

ManitobaMoose
Quartz | Level 8

Ok Did the code I provide give you the same errors? Also, when writing infile datalines truncover, I assume this references the datalines from review.Benzene_levels, not from expose.

 

Anyway, no matter what I will accept your solution and give you points. Just trying to understand this. Thanks for your help.

novinosrin
Tourmaline | Level 20

@ManitobaMoose Haha, no you should NOT accept as solution that's not convincing. These credits definitely don't matter, it's just for learning.

Be right back in a bit  with a detailed explanation as I am having a burger on one hand, and am finding hard to type

 

 

novinosrin
Tourmaline | Level 20

Notes:

  1. Array statement complies a multidimensional array with 6 rows (1944:1949) being the range and times 5 makes it 30 columns -> 6*5
  2. On your first iteration when _n_=1, your input statement starts reading raw data from datalines or an external file if specified in a infile statement
  3. When point 2 _n_=1 becomes true, the nested loop iterates 6*5=30 times meaning 5 times for each year populating each element of the array one by one
  4. Temporary array retains values across of observations until sas processes each and every record
  5. Your set statement reads data from your input dataset expose and that’s where values of jobcode are referred from, using which new variable job is created with an assignment statement

I deeply apologize for the infile datalines truncover. This shouldn’t be used as you need the input statement to read the next line by default. Like @Astounding pointed out, you actually need another datalines to read and populate array for the dimension year(1949,1……5)

However since you have only 5 datalines, sas can’t find or read the line to populate for the year 1949.

So the correction is do year=1944 to 1948; instead of 1949

And now run and examine the corrected version below:

Data Benzene_Levels ; 

	Array Level{1944:1948,5}   ; /*populates two dimensional array*/
	retain level;
   if _n_ = 1 then do Year = 1944 to 1948;

      do Job = 1 to 5;
         input level{Year,Job} @ ; 
      end;
   end;
   set expose;
   /* Compute the job code index from the JobCode value */
   Job = input(translate(Jobcode,'12345','ABCDE'),1.);
   Benzene = level{Year,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
;
ManitobaMoose
Quartz | Level 8

Ok. Great. Now it make sense. The data set learn.update is from the Book Learning SAS by Example, and it worked, but it appears that the array range for year should have been 1944 to 1948. Perhaps it is an error in the book, even though it seems to work. At any rate, it appears that this is the genesis of the problem. Everything works now. Excellent learning experience. Thanks for your help.

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

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