Date: Tue, 11 May 2010 10:26:37 -0400
Reply-To: Chang Chung <chang_y_chung@HOTMAIL.COM>
Sender: "SAS(r) Discussion" <SAS-L@LISTSERV.UGA.EDU>
From: Chang Chung <chang_y_chung@HOTMAIL.COM>
Subject: Re: Alternative for "goto" in do loop
On Mon, 10 May 2010 23:12:33 -0400, Sid N <nsid31@GMAIL.COM> wrote:
>Hi,
>
>I am trying to understand the "goto" sequences in the second data step
>below:
>
>data range1;
>informat start end date9.;
>format start end date9.;
>input start end;
>start_m = month(start);
>end_m = month(end);
>start_y = year(start);
>end_y = year(end);
>cards;
>01JAN1975 01JAN1977
>01AUG1979 01JUL1980
>01MAR2008 01JAN2010
>01DEC2000 01SEP2002
>01FEB2010 01NOV2011
>;
>run;
>
>data range2;
>set range1;
>do y = start_y to end_y by 1;
>if y < 1980 then goto skip3;
>if y > 2009 then goto skip2;
> do m = 1 to 12 by 1;
> if (start_m > m and y = start_y) then goto skip1;
> if (y = end_y and end_m < m) then goto skip2;
> output;
> skip1:;
> end;
>skip3:;
>end;
>skip2:;
>run;
>
>
>Can someone please help me understand the "goto" sequences in the above "do
>loop"? I have heard that using "goto" sequences may not be an efficient way
>to code in SAS. Please suggest an alternative to output what the above code
>is accomplishing using different programming logic.
Hi, sid:
The data step range2 must have written by someone who does not know SAS at
all, not to mention the date/time programming.
It seems that the purpose of the step is to output as many observations as
the number of months between the given interval, inclusively at both ends.
It also seems that the interval is to be truncated if it goes outside of
another range, jan1980-dec2009. If this is the case, then one can code
it SAS way like below. I did not understand what the variable m in the
range2 is for, so I changed it to something more useful in my data step.
Ran on 9.2(TS1M0) on W32_VSPRO. HTH.
Cheers,
Chang
/* test data */
data range1;
informat start end date9.;
format start end date9.;
input start end;
start_m = month(start);
end_m = month(end);
start_y = year(start);
end_y = year(end);
cards;
01JAN1975 01JAN1977
01AUG1979 01JUL1980
01MAR2008 01JAN2010
01DEC2000 01SEP2002
01FEB2010 01NOV2011
;
run;
/* this will never pass any SAS code review session! */
data range2;
set range1;
do y = start_y to end_y by 1;
if y < 1980 then goto skip3;
if y > 2009 then goto skip2;
do m = 1 to 12 by 1;
if (start_m > m and y = start_y) then goto skip1;
if (y = end_y and end_m < m) then goto skip2;
output;
skip1:;
end;
skip3:;
end;
skip2:;
run;
/* a rewrite of data step above. a SAS way */
data range3;
set range1(keep= start end);
begin_month = max(start, '01jan1980'd);
end_month = min(end, '01dec2009'd);
m = begin_month;
do while (m <= end_month);
output;
m = intnx('month', m, 1);
end;
keep start end m;
format m yymmn7.;
run;
/* check */
proc compare base=range2(keep=start end) compare=range3;
run;
/* on lst
NOTE: No unequal values were found. All values compared are exactly equal.
*/
proc print data=range3(obs=30);
run;
/* on lst
Obs start end m
1 01AUG1979 01JUL1980 198001
2 01AUG1979 01JUL1980 198002
3 01AUG1979 01JUL1980 198003
4 01AUG1979 01JUL1980 198004
5 01AUG1979 01JUL1980 198005
6 01AUG1979 01JUL1980 198006
7 01AUG1979 01JUL1980 198007
8 01MAR2008 01JAN2010 200803
9 01MAR2008 01JAN2010 200804
10 01MAR2008 01JAN2010 200805
11 01MAR2008 01JAN2010 200806
12 01MAR2008 01JAN2010 200807
13 01MAR2008 01JAN2010 200808
14 01MAR2008 01JAN2010 200809
15 01MAR2008 01JAN2010 200810
16 01MAR2008 01JAN2010 200811
17 01MAR2008 01JAN2010 200812
18 01MAR2008 01JAN2010 200901
19 01MAR2008 01JAN2010 200902
20 01MAR2008 01JAN2010 200903
21 01MAR2008 01JAN2010 200904
22 01MAR2008 01JAN2010 200905
23 01MAR2008 01JAN2010 200906
24 01MAR2008 01JAN2010 200907
25 01MAR2008 01JAN2010 200908
26 01MAR2008 01JAN2010 200909
27 01MAR2008 01JAN2010 200910
28 01MAR2008 01JAN2010 200911
29 01MAR2008 01JAN2010 200912
30 01DEC2000 01SEP2002 200012
*/