<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: Macro with varying number of arguments? in Advanced Programming</title>
    <link>https://communities.sas.com/t5/Advanced-Programming/Macro-with-varying-number-of-arguments/m-p/701282#M29</link>
    <description>&lt;P&gt;Get this list of combinations. PROC SORT is handy.&amp;nbsp; Use the list to write code.&amp;nbsp; An efficient way to write code for splitting a dataset is to use a single data step with multiple output statements.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data out1 out2 out3 ;
  set in;
  if condition1 then output out1;
  else if condition2 then output out2;
  else output out3 ;
run;&lt;/CODE&gt;&lt;/PRE&gt;</description>
    <pubDate>Tue, 24 Nov 2020 16:55:49 GMT</pubDate>
    <dc:creator>Tom</dc:creator>
    <dc:date>2020-11-24T16:55:49Z</dc:date>
    <item>
      <title>Macro with varying number of arguments?</title>
      <link>https://communities.sas.com/t5/Advanced-Programming/Macro-with-varying-number-of-arguments/m-p/701273#M27</link>
      <description>&lt;P&gt;The following code imports a csv file and selects the unique values for each element of VList into macrovariables Var1, Var2 etc.&amp;nbsp; &amp;nbsp;Then it creates a new table for each unique combination of the values in Var1 Var2 from the original CSV file.&amp;nbsp;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I've written the code so it works with 2 elements in VList.&amp;nbsp; But i need it to work for a varying number of elements.&amp;nbsp;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Right now i have 2 distinct macros to loop through each of the elements of Var1 and Var2 (Loop_A, Loop_B), and the macro Combo to create the new table from the distinct combinations.&amp;nbsp; If the number of elements in VList varies, then i would need a varying number of Loop_X's, and Combo would need a varying number of arguments.&amp;nbsp;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Any suggestions on how to accomplish this?&amp;nbsp;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;
%LET InFile=C:\FilePath\Filename.CSV;
%LET VList=Variable1|Variable2;
%LET VNum=%SYSFUNC(CountW(&amp;amp;VList.));
%PUT VNUM=&amp;amp;VNum.;

proc import datafile="&amp;amp;Infile."
	DBMS=csv out=CSV_IN replace;
	guessingrows=1000;
run;

%MACRO MVars(VarList);
	%DO K=1 %TO &amp;amp;VNum.;
		%GLOBAL V&amp;amp;K.;

		*creates V1 as first variable in the VList, V2 as the 2nd...etc;
		%LET V&amp;amp;K.= %SYSFUNC(SCAN(&amp;amp;VarList.,&amp;amp;K.,|));
		%PUT V&amp;amp;K.= &amp;amp;&amp;amp;V&amp;amp;K.;

		*Sorts CSV File by V#;
		proc sort data=CSV_IN;
			by &amp;amp;&amp;amp;V&amp;amp;K.;
		run;

		*creates a table the same name as the variable, and populates it with the first obs of each distinct input for that variable;
		data &amp;amp;&amp;amp;V&amp;amp;K.;
			set CSV_IN;
			by &amp;amp;&amp;amp;V&amp;amp;K;

			if first.&amp;amp;&amp;amp;V&amp;amp;K. then
				output;
		run;

		%GLOBAL Var&amp;amp;K.;

		*creates macrovariables Var1, Var2 etc. as the distinct values for V1, V2...;
		proc sql noprint;
			select &amp;amp;&amp;amp;V&amp;amp;K. into :Var&amp;amp;K. 
				separated by '|'
			from &amp;amp;&amp;amp;V&amp;amp;K.;
		quit;

		%PUT Var&amp;amp;K. = &amp;amp;&amp;amp;Var&amp;amp;K.;
	%END;
%MEND MVars;

%MVars(&amp;amp;VList.);

*Creates MacroVariables Length_1, Length_2 etc, as the number of items in each var#.;
%MACRO LengthOfVars();
	%DO L = 1 %TO &amp;amp;VNum.;
		%GLOBAL Length_&amp;amp;L.;
		%LET Length_&amp;amp;L. = %SYSFUNC(CountW(&amp;amp;&amp;amp;Var&amp;amp;L.,|));
		%PUT Length_&amp;amp;L. = &amp;amp;&amp;amp;Length_&amp;amp;L.;
	%END;
%MEND LengthOfVars;

%LengthofVars();

*Loop_A and Loop_B cycle through every combination of the distinct values for each var#;
%MACRO LOOP_A();
	%DO A = 1 %TO &amp;amp;Length_1.;
		%LET AA = %SCAN(&amp;amp;Var1.,&amp;amp;A.,|);
		%PUT AA=&amp;amp;AA.;

		%LOOP_B;
	%END;
%MEND LOOP_A;

%MACRO LOOP_B();
	%DO B = 1 %TO &amp;amp;Length_2.;
		%LET BB = %SCAN(&amp;amp;Var2.,&amp;amp;B.,|);
		%PUT BB=&amp;amp;BB.;

		%COMBO(&amp;amp;AA.,&amp;amp;BB.);
	%END;
%MEND LOOP_B;

*create a new table for each unique combination of variable values;
%MACRO Combo(FirstVar, SecondVar);

	Proc sql noprint;
		create table NewTable_&amp;amp;FirstVar._&amp;amp;SecondVar.
			as select * from CSV_IN
		where &amp;amp;V1.="&amp;amp;FirstVar." and &amp;amp;V2.=&amp;amp;SecondVar.;
	quit;&lt;BR /&gt;        %PUT &amp;amp;V1. &amp;amp;FirstVar. &amp;amp;V2. &amp;amp;SecondVar.;

%MEND COMBO;&lt;BR /&gt;
%LOOP_A;&lt;/CODE&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Tue, 24 Nov 2020 16:37:13 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Advanced-Programming/Macro-with-varying-number-of-arguments/m-p/701273#M27</guid>
      <dc:creator>mcook</dc:creator>
      <dc:date>2020-11-24T16:37:13Z</dc:date>
    </item>
    <item>
      <title>Re: Macro with varying number of arguments?</title>
      <link>https://communities.sas.com/t5/Advanced-Programming/Macro-with-varying-number-of-arguments/m-p/701278#M28</link>
      <description>&lt;P&gt;It is hard to see the forest here.&amp;nbsp; Can you explain what code you are trying to use the macro language to generate?&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;You seem to be saying you want this to be based on the values of two VARIABLES (not macro variables).&lt;/P&gt;
&lt;P&gt;You can use any number of methods to get the distinct set of values of two variables. For example you could use PROC FREQ or PROC SORT or PROC SQL.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;proc freq data=sashelp.cars ;
tables origin*type / noprint missing out=combo;
run;
proc sort data=sashelp.cars(keep=origin type) out=combo nodupkey;
  by origin type;
run;
proc sql;
create table combo as select distinct origin,type from sashelp.cars;
quit;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Once you have this list of combinations you can then use it to drive the generation of whatever code you want.&lt;/P&gt;
&lt;P&gt;So what code would you want to generate for the first combination? The second?&lt;/P&gt;</description>
      <pubDate>Tue, 24 Nov 2020 16:50:13 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Advanced-Programming/Macro-with-varying-number-of-arguments/m-p/701278#M28</guid>
      <dc:creator>Tom</dc:creator>
      <dc:date>2020-11-24T16:50:13Z</dc:date>
    </item>
    <item>
      <title>Re: Macro with varying number of arguments?</title>
      <link>https://communities.sas.com/t5/Advanced-Programming/Macro-with-varying-number-of-arguments/m-p/701282#M29</link>
      <description>&lt;P&gt;Get this list of combinations. PROC SORT is handy.&amp;nbsp; Use the list to write code.&amp;nbsp; An efficient way to write code for splitting a dataset is to use a single data step with multiple output statements.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data out1 out2 out3 ;
  set in;
  if condition1 then output out1;
  else if condition2 then output out2;
  else output out3 ;
run;&lt;/CODE&gt;&lt;/PRE&gt;</description>
      <pubDate>Tue, 24 Nov 2020 16:55:49 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Advanced-Programming/Macro-with-varying-number-of-arguments/m-p/701282#M29</guid>
      <dc:creator>Tom</dc:creator>
      <dc:date>2020-11-24T16:55:49Z</dc:date>
    </item>
    <item>
      <title>Re: Macro with varying number of arguments?</title>
      <link>https://communities.sas.com/t5/Advanced-Programming/Macro-with-varying-number-of-arguments/m-p/701284#M30</link>
      <description>&lt;P&gt;So here is one way.&amp;nbsp; This macro assumes that the variables are all character.&amp;nbsp; I will leave it as an exercise to see how to adapt the code to allow numeric variables and/or combinations of many types.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%macro split(indsn,varlist,basename=split);
%local i var sep;
proc sort data=&amp;amp;indsn(keep=&amp;amp;varlist) out=combos nodupkey;
  by &amp;amp;varlist;
run;

filename code temp;
data _null_;
  file code lrecl=75 ;
  put 'data ' @;
  do _n_=1 by 1 until(eof1);
    set combos end=eof1 ;
    put "&amp;amp;basename" _n_ @ ;
  end;
  put ';' / "  set &amp;amp;indsn;" ;
  do _n_=1 by 1 until(eof2);
    set combos end=eof2 ;
    if _n_ &amp;gt; 1 then put 'else ' @;
    put 'if (' 
%do i=1 %to %sysfunc(countw(&amp;amp;varlist));
  %let var=%scan(&amp;amp;varlist,&amp;amp;i);
  &amp;amp;sep &amp;amp;var= :$quote. 
  %let sep='and ';
%end;
      ") then output &amp;amp;basename" _n_ ';'
    ;
  end;
  put 'run;';
  stop;
run;
%include code ;
%mend split;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Example run:&lt;/P&gt;
&lt;PRE&gt;335   options mprint;
336   %split(sashelp.cars,origin type)
MPRINT(SPLIT):   proc sort data=sashelp.cars(keep=origin type) out=combos nodupkey;
MPRINT(SPLIT):   by origin type;
MPRINT(SPLIT):   run;

NOTE: There were 428 observations read from the data set SASHELP.CARS.
NOTE: 413 observations with duplicate key values were deleted.
NOTE: The data set WORK.COMBOS has 15 observations and 2 variables.
NOTE: PROCEDURE SORT used (Total process time):
      real time           0.01 seconds
      cpu time            0.00 seconds


MPRINT(SPLIT):   filename code temp;
MPRINT(SPLIT):   data _null_;
MPRINT(SPLIT):   file code lrecl=75 ;
MPRINT(SPLIT):   put 'data ' @;
MPRINT(SPLIT):   do _n_=1 by 1 until(eof1);
MPRINT(SPLIT):   set combos end=eof1 ;
MPRINT(SPLIT):   put "split" _n_ @ ;
MPRINT(SPLIT):   end;
MPRINT(SPLIT):   put ';' / "  set sashelp.cars;" ;
MPRINT(SPLIT):   do _n_=1 by 1 until(eof2);
MPRINT(SPLIT):   set combos end=eof2 ;
MPRINT(SPLIT):   if _n_ &amp;gt; 1 then put 'else ' @;
MPRINT(SPLIT):   put 'if (' origin= :$quote. 'and ' type= :$quote. ") then output split" _n_ ';' ;
MPRINT(SPLIT):   end;
MPRINT(SPLIT):   put 'run;';
MPRINT(SPLIT):   stop;
MPRINT(SPLIT):   run;

NOTE: The file CODE is:
      Filename=C:\Users\...\#LN00063,
      RECFM=V,LRECL=75,File Size (bytes)=0,
      Last Modified=24Nov2020:12:14:19,
      Create Time=24Nov2020:12:14:19

NOTE: 19 records were written to the file CODE.
      The minimum record length was 4.
      The maximum record length was 75.
NOTE: There were 15 observations read from the data set WORK.COMBOS.
NOTE: There were 15 observations read from the data set WORK.COMBOS.
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds


MPRINT(SPLIT):   data split1 split2 split3 split4 split5 split6 split7 split8 split9 split10 split11
split12 split13 split14 split15 ;
MPRINT(SPLIT):   set sashelp.cars;
MPRINT(SPLIT):   if (Origin="Asia" and Type="Hybrid" ) then output split1 ;
MPRINT(SPLIT):   else if (Origin="Asia" and Type="SUV" ) then output split2 ;
MPRINT(SPLIT):   else if (Origin="Asia" and Type="Sedan" ) then output split3 ;
MPRINT(SPLIT):   else if (Origin="Asia" and Type="Sports" ) then output split4 ;
MPRINT(SPLIT):   else if (Origin="Asia" and Type="Truck" ) then output split5 ;
MPRINT(SPLIT):   else if (Origin="Asia" and Type="Wagon" ) then output split6 ;
MPRINT(SPLIT):   else if (Origin="Europe" and Type="SUV" ) then output split7 ;
MPRINT(SPLIT):   else if (Origin="Europe" and Type="Sedan" ) then output split8 ;
MPRINT(SPLIT):   else if (Origin="Europe" and Type="Sports" ) then output split9 ;
MPRINT(SPLIT):   else if (Origin="Europe" and Type="Wagon" ) then output split10 ;
MPRINT(SPLIT):   else if (Origin="USA" and Type="SUV" ) then output split11 ;
MPRINT(SPLIT):   else if (Origin="USA" and Type="Sedan" ) then output split12 ;
MPRINT(SPLIT):   else if (Origin="USA" and Type="Sports" ) then output split13 ;
MPRINT(SPLIT):   else if (Origin="USA" and Type="Truck" ) then output split14 ;
MPRINT(SPLIT):   else if (Origin="USA" and Type="Wagon" ) then output split15 ;
MPRINT(SPLIT):   run;

NOTE: There were 428 observations read from the data set SASHELP.CARS.
NOTE: The data set WORK.SPLIT1 has 3 observations and 15 variables.
NOTE: The data set WORK.SPLIT2 has 25 observations and 15 variables.
NOTE: The data set WORK.SPLIT3 has 94 observations and 15 variables.
NOTE: The data set WORK.SPLIT4 has 17 observations and 15 variables.
NOTE: The data set WORK.SPLIT5 has 8 observations and 15 variables.
NOTE: The data set WORK.SPLIT6 has 11 observations and 15 variables.
NOTE: The data set WORK.SPLIT7 has 10 observations and 15 variables.
NOTE: The data set WORK.SPLIT8 has 78 observations and 15 variables.
NOTE: The data set WORK.SPLIT9 has 23 observations and 15 variables.
NOTE: The data set WORK.SPLIT10 has 12 observations and 15 variables.
NOTE: The data set WORK.SPLIT11 has 25 observations and 15 variables.
NOTE: The data set WORK.SPLIT12 has 90 observations and 15 variables.
NOTE: The data set WORK.SPLIT13 has 9 observations and 15 variables.
NOTE: The data set WORK.SPLIT14 has 16 observations and 15 variables.
NOTE: The data set WORK.SPLIT15 has 7 observations and 15 variables.
NOTE: DATA statement used (Total process time):
      real time           0.09 seconds
      cpu time            0.09 seconds
&lt;/PRE&gt;</description>
      <pubDate>Tue, 24 Nov 2020 17:32:42 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Advanced-Programming/Macro-with-varying-number-of-arguments/m-p/701284#M30</guid>
      <dc:creator>Tom</dc:creator>
      <dc:date>2020-11-24T17:32:42Z</dc:date>
    </item>
    <item>
      <title>Re: Macro with varying number of arguments?</title>
      <link>https://communities.sas.com/t5/Advanced-Programming/Macro-with-varying-number-of-arguments/m-p/701315#M35</link>
      <description>&lt;P&gt;In&amp;nbsp;&lt;/P&gt;
&lt;PRE class="language-sas"&gt;&lt;CODE&gt;%LET VList=Variable1|Variable2;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;where are you getting these Variable1 &amp;amp; Variable2 from? If it's from a SAS table, perhaps consider using dictionary.columns with PROC SQL to create a macro variable with a dynamic list of columns separated by an appropriate delimiter. Then, use the &amp;amp;sqlobs instead of &amp;amp;VNUM as the ending point of a %DO loop (This will replace both 2nd and 3rd %let statements in your code as well).&lt;/P&gt;</description>
      <pubDate>Tue, 24 Nov 2020 18:20:55 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Advanced-Programming/Macro-with-varying-number-of-arguments/m-p/701315#M35</guid>
      <dc:creator>SuCheeTay</dc:creator>
      <dc:date>2020-11-24T18:20:55Z</dc:date>
    </item>
  </channel>
</rss>

