Hello I am using the following code:
%macro test;
%ARRAY(yrs,VALUES=1983-1986);
%let Temp= %DO_OVER(yrs);
%mend test;
%test;
%put &Temp;
Here's my sas log:
1 %_eg_hidenotesandsource;
5 %_eg_hidenotesandsource;
22
23 %macro test;
24 %ARRAY(yrs,VALUES=1983-1986);
25 %let Temp= %DO_OVER(yrs);
26 %mend test;
27 %test;
NOTE: Line generated by the invoked macro "TEST".
27 %ARRAY(yrs,VALUES=1983-1986);
_
180
WARNING: Apparent invocation of macro ARRAY not resolved.
ERROR 180-322: Statement is not valid or it is used out of proper order.
WARNING: Apparent invocation of macro DO_OVER not resolved.
WARNING: Apparent invocation of macro DO_OVER not resolved.
28 %put &Temp;
%DO_OVER(yrs)
29
30 %_eg_hidenotesandsource;
42
43
44 %_eg_hidenotesandsource;
47
My software does not seems te recognized %array and %do_over;
First question: Why?
If it is not possible to correct this situation, what can I do to achieve the same task?
Regards,
Alain
"Why?" - this is simple, there is no such thing as %array in the SAS language, either in Base SAS or Macro SAS, therefore the operation is invalid. Nor in fact is there a %do_over function in the SAS language.
Question from me, why do data processing in a text generation language in the first place? Datastep (Base) is the language in which data processing is done, and that has all the constructs such as arrays for such a purpose. Macro language only creates text, it doesn't do anything itself. You can use a few constructs in Macro, such as:
%do i=1983 %to 1986; ... %end;
However these are pretty basic and are only creating text at the end of the day.
Those are not SAS provided macros. You need to tell SAS how to find the definition of those macros. Either %INCLUDE the source code or setup SASAUTOS to point to the location where SAS can find the source code.
%array and %do_over do not, as far as I know, exist. Let us know what you're trying to accomplish (with example have and want datasteps) and someone will be able to show you how to do it.
Art, CEO, AnalystFinder.com
What the purpose of the attached pdf document if the macro %do_over and %array do not exist?
Anyway...
What I would like to do is to make two macro variables which contains a list of values such as:
%let list1=15020 54330 54350 55080 65110 68020 80110
%let list2= 54090 54320 55020 80100 80110 80180 80200 90010
I would like to put those two macro variables at the begining of the sas program to permits the user to see those code and to change those if necessary.
There after, I would like to use those two macro variables in order to reproduce the code below, using a do loop statement.
It is why I have looked at the %array and %do_over, macro function that does not exist.
Does anyone could provide me such suggestions?
Regards
Alain
data donneesTrans (drop=totIndUnRisq totVed i);
length ind15020 ind54330 ind54350 ind55080 ind65110 ind68020 ind80110
ved54090 ved54320 ved55020 ved80100 ved80110 ved80180 ved80200 ved90010 4;
set donneesTrans;
array unite{*} unite1-unite&DimVect;
do i=1 to &DimVect;
if unite(i)=15020 then ind15020=1;
if unite(i)=54330 then ind54330=1;
if unite(i)=54350 then ind54350=1;
if unite(i)=55080 then ind55080=1;
if unite(i)=65110 then ind65110=1;
if unite(i)=68020 then ind68020=1;
if unite(i)=80110 then ind80110=1;
if unite(i)=54090 then ved54090=1;
if unite(i)=54320 then ved54320=1;
if unite(i)=55020 then ved55020=1;
if unite(i)=80100 then ved80100=1;
if unite(i)=80110 then ved80110=1;
if unite(i)=80180 then ved80180=1;
if unite(i)=80200 then ved80200=1;
if unite(i)=90010 then ved90010=1;
end;
if ind15020=. then ind15020=0;
if ind54330=. then ind54330=0;
if ind54350=. then ind54350=0;
if ind55080=. then ind55080=0;
if ind65110=. then ind65110=0;
if ind68020=. then ind68020=0;
if ind80110=. then ind80110=0;
if ved54090=. then ved54090=0;
if ved54320=. then ved54320=0;
if ved55020=. then ved55020=0;
if ved80100=. then ved80100=0;
if ved80110=. then ved80110=0;
if ved80180=. then ved80180=0;
if ved80200=. then ved80200=0;
if ved90010=. then ved90010=0;
run;
Actually, they both exist but aren't macro functions, per se, but rather macros written by a SAS user. They can be downloaded from:http://www.sascommunity.org/wiki/File:Clay-TightLooping-macros.zip
If your not familiar with SAS macros, you have to first download and unzip the file, then run the two (or if you want, all three macros).
Then you can use them as described in the paper about them.
Art, CEO, AnalystFinder.com
Thank you for providing me the web site where to download those macro.
Regards,
Alain
Firstly, you can halve your code straight off by using ifn/ifc functions:
data donneesTrans (drop=totIndUnRisq totVed i); length ind15020 ind54330 ind54350 ind55080 ind65110 ind68020 ind80110 ved54090 ved54320 ved55020 ved80100 ved80110 ved80180 ved80200 ved90010 4; set donneesTrans; array unite{*} unite1-unite&DimVect; do i=1 to &DimVect; ind1520=ifn(unite(i)=15020,1,0); ind5430=ifn(unite(i)=54330,1,0); ... end; run;
This way you don't need the second part for setting the zeros.
Second point, putting data into macro lists is rarely a good idea, it can both bloat the code you need to do (i.e. all the looping over an such like) and make hard to maintain code. Put your lists into datasets - datasets are there to hold data. Then you merge data together and process. So say I have the lists as:
LIST_NO LIST1 LIST2 ...
1 15020 54330...
2 54090 54320...
It is then a pretty simple task to merge either of those lists onto the data and then code the check as:
data want; merge have lists (where=(list_no=1)); array unite{*} unite:; /* Note the shorthand use of : to indicate */ array list{*} list:; /* all variables starting with the text */ do i=1 to dim(unite); do j=1 to dim(list); if unite{i}=list{j} then found_value=list{j}; end; end; run;
This just loops over list and sets foun variable to value if it matches. Very simple, short logic.
Very good comments. I will take that into consideration for the future.
Regards,
Alain
Hello,
I agree with you, putting a list of values into a macro variable may not be in certain circumstance, the best thing to do.
I have read your message attentively.
What I have done its to put my code in a dataset as recommended. At the end, I have two different datasets, one containing the numeric code and another one containing the alphanumeric code. Ex;
Table1
10010
10020
And so on.
Table2
Ved10010
Ved10020
And so on
Thereafter, I have use proc transpose (out = Liste) with table2 which permit me to obtain the following dataset
Ved10010 Ved10020 … and so on.
Table3 contains the variables unite from Unite1 – Unite13;
I have made a merge of table3 and Liste to get a dataset (Table4) as below:
Unite1 Unite2 Unite3 …Unite13 ved10010 ved10020…Ind80800 and so so.
Thereafter, I would like to initialize all the variable starting by ved or ind to zero.
Then, what I would like to do its to check for each observation of dataset Table4 if the values for the variable Unite1 to Unite13 can be found in values of table1 and if so the variable ved or ind would have the value of one.
Ex;
If the value of 10010 is found in one of the value Unites1 to Unite13 then ind10010 will have the value of one otherwise, ind10010 is zero.
I have made few tests with the arrays and I am losing the original value of Unite1 to Unite13 (reset to zero) and I am not able to assign a value of one or zero to ind10010 and so on.
What’s wrong with my arrays??
Regards,
Alain.
@alepage wrote:
Hello,
I agree with you, putting a list of values into a macro variable may not be in certain circumstance, the best thing to do.
I have read your message attentively.
What I have done its to put my code in a dataset as recommended. At the end, I have two different datasets, one containing the numeric code and another one containing the alphanumeric code. Ex;
Table1
10010
10020
And so on.
Table2
Ved10010
Ved10020
And so on
Thereafter, I have use proc transpose (out = Liste) with table2 which permit me to obtain the following dataset
Ved10010 Ved10020 … and so on.
Table3 contains the variables unite from Unite1 – Unite13;
I have made a merge of table3 and Liste to get a dataset (Table4) as below:
Unite1 Unite2 Unite3 …Unite13 ved10010 ved10020…Ind80800 and so so.
Thereafter, I would like to initialize all the variable starting by ved or ind to zero.
Then, what I would like to do its to check for each observation of dataset Table4 if the values for the variable Unite1 to Unite13 can be found in values of table1 and if so the variable ved or ind would have the value of one.
Ex;
If the value of 10010 is found in one of the value Unites1 to Unite13 then ind10010 will have the value of one otherwise, ind10010 is zero.
I have made few tests with the arrays and I am losing the original value of Unite1 to Unite13 (reset to zero) and I am not able to assign a value of one or zero to ind10010 and so on.
What’s wrong with my arrays??
Regards,
Alain.
That sounds even worse than the original approach. Instead make everything vertical. Then summarize and transpose if you want.
So the data you want to search looks something like this. So instead of columns named UNITE1 to UNITEn you have up to N rows with two columns one with the value, call it UNITE, and one with the index, call it ROW.
data facts ;
input id row unite ;
cards;
1 1 101
1 2 102
2 1 201
2 2 101
2 3 102
;
Then the data you want to search for looks something like this.
data search ;
input prefix $ value ;
cards;
ved 101
ved 102
ved 103
ved 201
;
Now combine them an aggregate to the ID* search term level. Also generate a dummy set of zeros for the ones that are not found and re-merge to two sets. You can then transpose back to your wide format if you need it for some other purpose.
proc sql ;
create table matches as
select a.id,b.prefix,b.value
, max(case when b.value = a.unite then 1 else 0 end) as found
from facts a inner join search b
on a.unite = b.value
group by 1,2,3
order by 1,2,3
;
create table dummy as
select a.id,b.prefix,b.value,0 as found
from (select distinct id from facts) a
full join search b
on 1=1
order by 1,2,3
;
quit;
data want ;
merge dummy matches ;
by id prefix value ;
run;
proc print;
run;
proc transpose data=want out=report ;
by id ;
id prefix value ;
var found ;
run;
proc print;
run;
Obs id prefix value found 1 1 ved 101 1 2 1 ved 102 1 3 1 ved 103 0 4 1 ved 201 0 5 2 ved 101 1 6 2 ved 102 1 7 2 ved 103 0 8 2 ved 201 1 Obs id _NAME_ ved101 ved102 ved103 ved201 1 1 found 1 1 0 0 2 2 found 1 1 0 1
It is best not to use code generation (macros) to do things that you can do directly with SAS.
In this case it looks like you want to input two lists of code values (IND and VED) and generate series of flag variables to indicate if those codes appear in the set of input variables (UNITE1 ....).
It would probably be better to produce mulitple observations instead of multiple columns with the code value stored in the variable name. But even with this wide structure you do not need to resort to macro looping. Instead just use macro functions to generate the dynamic variable names.
%* Set the code lists ;
%let indlist=15020 54330 54350 55080;
%let vedlist=54090 54320 55020 80100;
%* generate variable names from code lists;
%let indvars=ind%sysfunc(tranwrd(%sysfunc(compbl(&codelist)),%str( ),%str( ind)));
%let vedvars=ved%sysfunc(tranwrd(%sysfunc(compbl(&codelist)),%str( ),%str( ved)));
%* Need count to generate _temporary_ array ;
%let nflags=%sysfunc(countw(&indlist &vedlist));
data want;
set have;
array flags 4 &indvars &vedvars;
array values (&nflags) _temporary_ (&indlist &vedlist);
do i=1 to dim(flags);
flags(i) = 0<whichn(values(i),of unite1-unite&DimVect);
end;
drop i;
run;
Thanks for the SAS program.
Regards,
Alain
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
What’s the difference between SAS Enterprise Guide and SAS Studio? How are they similar? Just ask SAS’ Danny Modlin.
Find more tutorials on the SAS Users YouTube channel.