Suzie,
Like Paul I am a bit of a pragmatist harboring a purist's conscience.
It is worth considering whether you have chosen to loop at the correct
level. The code
data y.&outvar&tkn;
set x.events&tkn;
is often a danger sign that your data structure design will require much
macro code to manage a poor design. The problem is that you are creating
data sets Y.&OUTVAR&TKN where information has been buried in the data set
names. Consequently, just as your data sets X.EVENTS&TKN have required you
to make a macro looping over these data sets, your solution will continue
to demand that you write such macros. Of course, the good news is that you
will get much better at writing such macros. The bad news is that might
find it continually necessary to write them, and never realize that the
source of this requirement is a data structure problem.
If the data sets, X.EVENTS&TKN, have the same structure then it probably
would be better to create one data set with all the information stored in
variables. The purist's view of the problem might produce the following
code.
%macro source_names ( pref=x.events, dayparts= , nsourcev=nds) ;
%* return list of data sets with in= options
and set &NSOURCEEV= number of elements
*;
%local i tkn list ;
%do i = 1 %to 999999 ;
%let tkn = %scan (&dayparts, &i) ;
%if %length (&tkn) = 0 %then %goto iend ;
%let list = &list &pref&tkn(in = in&tkn) ;
%end ;
%iend:
%let &NSOURCEV = %eval(&i-1) ;
&list
%mend source_names ;
%macro source ( nv=1 , pref=in) ;
%* return formula for source variable *;
%local list i ;
%do i = 1 %to &nv ;
%let list = &list + &i*in&i ;
%end ;
0 /* + */ &list
%mend source ;
%macro vodp1_daily (dayparts=,outvar=);
%local nds ;
data y.&outvar ( drop = __i ) ;
length day $ 6 var $ 32 ;
retain var "&outvar" ;
set %source_names ( dayparts = &dayparts, nsourcev=nds ) ;
__i = %source ( nv=&nds ) ;
day = scan("&dayparts", __i) ;
run ;
%mend vodp1_daily ;
%vodp1_daily(dayparts=5 26 69 917 1720 2023 232, outvar=vodq)
Clearly the above code is more complex than either you or Paul suggested,
since it contains 3 macros instead of two and with more looping. On the
other hand, the first two macros can be considered the price paid for
conversion to a better structure; they can be easily tested with
%global nds ;
%put %source_names ( dayparts = 5 20 ) ;
%put &nds ;
%put %source ( nv=&nds) ;
and they reveal the true structure of the problem, list management. It is
left to macro programmer to build his own tools for list management
problems, since SAS macro does not provide these tools in a ready to use
form.
However, the pragmatist might argue that there is no need to violently
change the nature of the Paul's code, the above was designed to avoid
concatenation. What does an extra data pass to perform the concatenation
hurt?
%macro vodp1_daily (dayparts=,out=y.vodq);
%local i tkn ;
%do i = 1 %to 999999 ;
%let tkn = %scan (&dayparts, &i) ;
%if %length (&tkn) = 0 %then %goto iend ;
data temp;
length day $ 6 var $ 32 ;
retain var "%scan(&out,.)" ;
set x.events&tkn;
day = "&tkn" ;
run ;
proc append base = &out data = temp ;
run ;
%end ;
%iend:
%mend vodp1_daily ;
%vodp1_daily(dayparts=5 26 69 917 1720 2023 232, out=y.vodq)
In any case, I note that missing RUN statement in your code, later adopted
by Paul, is an error that may or may not bite as you continue to develop
your program, since it depends on the precise nature of the remaining code
and whether it is run interactively or in batch mode.
Well at least you have answers to your problem and things to think about
when confronting them. It probably will not matter much whether you adopt
the purist's solution, the pragmatist's solution or go with the many data
sets solution for this problem. The pragmatist can argue, get the job
done; and the purist can argue that it is worth preparing for the job's
where efficiency techniques will really matter; but it is the tension
between these two points of view that will make you a better programmer.
Ian Whitlock
================
Date: Thu, 19 Jan 2006 12:15:37 -0500
Reply-To: "Dorfman, Paul" <***@FCSO.COM>
Sender: "SAS(r) Discussion"
From: "Dorfman, Paul" <***@FCSO.COM>
Subject: Re: Macro do loop with discrete values
Susie,
You have to break up the list into tokens before a token canbe used. One
way would be
%local i tkn ;
%do i = 1 %to 999999 ;
%let tkn = %scan (&dayparts, &i) ;
%if %length (&tkn) = 0 %then %goto iend ;
data y.&outvar&tkn;
set x.events&tkn;
%end ;
%iend:
Purists consider suppliying a "large enough number", such as 999999 above a
kludge, preferring the better distilled
%local i tkn ;
%let i = 1 ;
%let tkn = %scan (&dayparts, &i) ;
%do %while (%length (&tkn) ne 0) ;
data y.&outvar&tkn;
set x.events&tkn;
%let i = %eval (&i + 1) ;
%let tkn = %scan (&dayparts, &i) ;
%end ;
but I am not sure at all that it is cleaner. I would rather stick with the
first approach, all the more that in all such cases, even 999999 is an
overkill - no list of this sort will ever contain as many tokens, but if
you are not sure about that, add another 9 <g>.
Kind regards
------------
Paul Dorfman
Jax, FL
------------
Post by Susie LiHello,
I have a use to create a macro to read datasets repeatedly. Part of the
input dataset names are designated numbers.
I don't know how to set it up in macro to read such data. In the
following example, I tried to use %do loop to do the job, but it did not
work, because SAS would require me to supply %to.
Please help.
-----
%let days=%str(5 26 69 917 1720 2023 232);
%macro vodp1_daily (dayparts=,outvar=);
%do i=&dayparts; /*dayparts*/
data y.&outvar&i;
set x.events&i;
%end;
run;
%mend%
%vodp1_daily(dayparts=&days,outvar=vodq)
---
Susie Li
TV Guide
1211 Avenue of the Americas
New York, NY 10036
Tel 212.852.7453