DATA Step, Macro, Functions and more

Array Two Similar Programs but only the first one works

Accepted Solution Solved
Reply
Frequent Contributor
Posts: 129
Accepted Solution

Array Two Similar Programs but only the first one works

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
 ;

 

 


Accepted Solutions
Solution
‎05-15-2018 04:18 PM
PROC Star
Posts: 1,800

Re: Array Two Similar Programs but only the first one works

Posted in reply to ManitobaMoose

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


All Replies
Super User
Posts: 6,767

Re: Array Two Similar Programs but only the first one works

Posted in reply to ManitobaMoose

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

PROC Star
Posts: 1,800

Re: Array Two Similar Programs but only the first one works

[ Edited ]
Posted in reply to ManitobaMoose
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
;
Frequent Contributor
Posts: 129

Re: Array Two Similar Programs but only the first one works

Posted in reply to novinosrin

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

PROC Star
Posts: 1,800

Re: Array Two Similar Programs but only the first one works

Posted in reply to ManitobaMoose

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

Frequent Contributor
Posts: 129

Re: Array Two Similar Programs but only the first one works

Posted in reply to novinosrin

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.

PROC Star
Posts: 1,800

Re: Array Two Similar Programs but only the first one works

Posted in reply to ManitobaMoose

@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

 

 

Solution
‎05-15-2018 04:18 PM
PROC Star
Posts: 1,800

Re: Array Two Similar Programs but only the first one works

Posted in reply to ManitobaMoose

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
;
Frequent Contributor
Posts: 129

Re: Array Two Similar Programs but only the first one works

Posted in reply to novinosrin

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.

☑ This topic is solved.

Need further help from the community? Please ask a new question.

Discussion stats
  • 8 replies
  • 192 views
  • 0 likes
  • 3 in conversation