0

I create a marco array using:

proc sql;
select distinct variable into:numVarList separated by ' ' from Map_num;

I used:

%put &numVarList{1};

and it gave me all variables:var1 var2 var3{1}

how to use index to pick out macro array variable?


update 20180305 it is strange that

%put &numVarList.;

then I got:age agenc_non_ccbt_fnd_bal chmtpd_tmpnt_bal crnyr_cnter_tdnum

%put %sysnc(scan(&numVarList.,1,str( )));

I got:age agnc_non_ccb

why?and how to fix it?

3 Answers 3

3

You do not create an array with your select. The result is just a string: var1 var2 var3

However you can access each element with the scan-function:

%let first_ele = %scan(&numVarList.,1,%str( ));

The result is: var1

You can also loop your string like this:

%do i=1 %to %sysfunc(countw(&numVarList.,%str( )));
   %put %scan(&numVarList.,&i.,%str( ));
%end;
Sign up to request clarification or add additional context in comments.

3 Comments

Yes, but how to built new macro variables and not only write their values to the log ?
I used your way,and I get a problem please check my question update.
Have you copied the string from another application? It could be a character that does not match with the encoding of your SAS software... Or maybe the problem is sysnc instead of sysfunc.
1

Concatenation of values

proc sql;
select distinct variable into:numVarList separated by ' ' from Map_num;

populates a single macro variable with a value, that can be construed as a list, which is a concatenation of the distinct values in the column named "variable".

For such a list you would scan out the individual items as shown by @zuluk.

In your case when the original values are names of variables, the resolution of the concatenation can be used directly as part of a SAS statement that accepts variable name lists, such as Proc PRINT; VAR &numVarList or DATA _NULL_; ARRAY v &numVarList

Macro array

The concept macro-array is simply a set of macro variables (which can be thought of as 'symbols' when too many 'variable' ideas are colliding) with a common basename and increasing numeric suffix. Such a set of macro variables is created by using a slightly different syntax in Proc SQL.

select distinct variable
into :symbol1-:symbol9999
from Map_num

The 9999 represents a large number that you do not expect to exceed. If the data has N <= 9999 rows then only N macro variable will be created. If N > 9999 rows only 9999 macro variables will be created. Caution: Too many macro variables can fill the macro symbol table and cause errors in your SAS. For me, Macro arrays are more a programming concept than a programming construct.

For example

Proc SQL noprint;
  select name into :name1-:name9999 from sashelp.class;
  %let name_count = &sqlobs;
quit;

%put NOTE: &=name1;
%put NOTE: &=name2;
%put NOTE: name&name_count=%superq(name&name_count);  * almost same as next;
%put NOTE: name&name_count=&&name&name_count;    * almost same as prev;

When dealing with the 'name' of the macro array in 1-level abstraction way, complete resolution is achieved by coding the 'tricky triple-hat' &&&

%macro log_macroArray (basename);
   %local i count_symbol value_symbol;
   %let count_symbol = &basename._count;

   %do i = 1 %to &&&count_symbol;
     %let value_symbol = &basename.&i;
     %put NOTE: &value_symbol=&&&value_symbol;
   %end;
%mend;

%log_macroArray(name);

The SAS macro system 'loops' internally during its value resolution phase and collapses the presence to && to & at each step of it's internal evaluation.

2 Comments

Note that you no longer need to provide the upper bound at all, just add the hyphen. select name into :name1- from sashelp.class;
@Tom Great tip! Now I know how to spot who has been reading the What's New document in each SAS release (not me)
0

Building on @zuluk's answer, you cannot use an operator (like { }) to access a macro "array" since it's not a part of the language and it's not possible to overload operators in SAS... mostly ... but you can do a function-style macro easily.

proc sql;
  select name into :namelist separated by ' '
  from sashelp.class;
quit;
%macro marray(list, n);
  %scan(&list.,&n.)
%mend marray;

%put %marray(&namelist,2);

That is pretty close to what you're looking for, just not quite the same syntax. If you then wanted to build new variables/etc., you could do so through the macro as well, though it might be more complicated to write a general macro given there are lots of ways you might want to do that. Here's a non-function-style version.

%macro m_to_array(list, n);
  *optionally - if you want to not specify n;
  %let n = %sysfunc(countw(&&&list));
  %do _i = 1 %to &n;
    %global &list.&_i.;
    %let &list.&_i. = %scan(&&&list.,&_i.);
  %end;
%mend m_to_array;

%m_to_array(namelist);
%put _global_;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.