Four methods of performing a look-ahead read
As is frequently the case, the discussion quickly morphed to a related topic; in this case, how to do a look-ahead read.
Jack Hamilton suggested the use of a second SET statement on the original data set, using the data set option FIRSTOBS=2. Richard DeVenezia submitted sample data and code using the BY statement; Jack submitted sample code that doesn't use a BY statement.
Here's the code to create the sample data:
data demo; input k $ val @@ ; cards; a 11 a 12 a 13 b 21 c 31 c 32 d 41 d 42 d 43 d 44 ;
Here's Jack's code:
data lookahead1 (drop=nextk); set demo end=endmain; if not endnext then set demo (firstobs=2 keep=k val rename=(k=nextk val=nextval)) end=endnext; if (k ne nextk) or endmain then nextval = .; run;
Here's Richard's code:
data lookahead2 (drop=i); set demo; by k; if (first.k or not last.k) then do i = 1 to 1 + (first.k and not last.k); set demo(keep=val rename=(val=nextval) ); end; if last.k then nextval = .; run;
Both methods produce the same output:
Obs k val nextval 1 a 11 12 2 a 12 13 3 a 13 . 4 b 21 . 5 c 31 32 6 c 32 . 7 d 41 42 8 d 42 43 9 d 43 44 10 d 44 .
Ed Heaton later posted a method, credited to Mike Rhoads, of using MERGE for the same effect, without the need to do a special check for the last observation:
Options mergeNoBy=noWarn ; Data lookahead1( drop=nextk ) ; Merge demo demo( firstObs=2 rename=( k=nextK val=nextVal ) ) ; ... Run ; Options mergeNoBy=error ;
Howard Schreier posted generalized code which looks ahead an arbitrary number of observations:
%let lookdepth = 2; data lookahead&LOOKDEPTH(drop = many count close_to_last i); do many = 1 by 1 until (last.k); set demo(keep=k); by k; end; do count = 1 to many; set demo; by k; close_to_last = (many - count) < &LOOKDEPTH ; if (first.k or not close_to_last) then do i = 1 to 1 + first.k * min(&LOOKDEPTH,many-1); set demo(keep=val rename=(val=ahead&LOOKDEPTH.val) ); end; if close_to_last then do; ahead&LOOKDEPTH.val = .; end; output; end; run;