Aug 25, 2013

SAS macro to split a macro variables values to multiple macro variables values and also get the split count into another variable

And also there could be other instances where you need to do the opposite i.e. split a macro variable values list into individual pieces and get them into a series of macro variable values. One can use the below macro for such a requirement.


/**************************************************************************************************************
* Macro_Name:   split_macrovalue                                                                       
*
* Purpose: this macro is used to split a macro and return series of macro variables
*         
*                                                                                                             
* Usage: %split_macrovalue(macvar,prefix,splitcnt,dlm=' ');
*
* Input_parameters: macvar - input macro var
*                   prefix - prefix of the macro vars to be created in sequence order...
*                   splitcnt - name of the macro vars to store the length of the macro variable
*                   dlm=     - delimiter in the string (default is comma i.e. ,)
*                                                                                                             
* Outputs:  None.                                                                                              
*                                                                                                             
* Returns:  None  
*
* Example:
*                                                     %let str1=he she me to 3 "some";
*                                                     %SplitMacroValue(str1,pre,strcnt,dlm=' ');
*                                                    
*                                                     %put pre1=&pre1 pre2=&pre2 pre3=&pre3 pre4=&pre4 pre5=&pre5 pre6=&pre6 ;
*                                                     %put strcnt=&strcnt;
*                                                                                                             
* Modules_called: None
*
* Maintenance_History:                                                                                       
*-------------------------------------------------------------------------------------------------------------*
*  Date:      |   Who:        |  Description:                                                                 *
*-------------------------------------------------------------------------------------------------------------*
* 12/14/2011  | Sharad        | Initial creation.                                                          *
*
*-------------------------------------------------------------------------------------------------------------*
* HeaderEnd:                                                                                                  *
**************************************************************************************************************/



%macro split_macrovalue(macvar,prefix,splitcnt,dlm=comma,printvalue=N);
%put Start macro split_macrovalue(&macvar,&prefix,&splitcnt,&dlm);

 %if %upcase(&dlm) eq COMMA %then %do; %let dlm=,; %end;
 %else %if %upcase(&dlm) eq PIPE %then %do; %let dlm=|; %end;
 %else %if %upcase(&dlm) eq SPACE %then %do; %let dlm=%str( ); %end;

 %global &splitcnt; /*create the global variable for storing the splitcount*/
 %let num=1; /*initialize a counter variable*/  

 %global &prefix# /*create the global variable for storing the first split*/
 %let &prefix&num=%scan(%superq(&macvar),%superq(num),%superq(dlm)); /*Scan the first value*/
/* %put value here is &&&prefix#*/

/* Remove the comment's to check the values */

      %if %index(%superq(&macvar),%superq(dlm)) gt 0 %then
      %do;
       
       %do %while(%length(&&&prefix&num) gt 0);
            %let &splitcnt=# /*Store the split count to the macro variable reqd*/            
          %let num=%eval(&num + 1);/*increment the counter*/        
          %global &prefix# /*create the global variable*/
          %let &prefix&num=%scan(%superq(&macvar),%superq(num),%superq(dlm)); /*scan the next value*/
/*        %put The next value is &prefix&num=&&&prefix# */
        %end;
      %end;
      %else
      %do; 
              %let &splitcnt=# /*Store the split count to the macro variable reqd*/ 
      %end;  

      %put The number of values are &&&splitcnt;

      /* Remove the comment's to check the values */
      %if &printvalue=Y %then
      %do;
          
            %do i=1 %to &&&splitcnt;
           %put &prefix&i = &&&prefix&i;
            %end;  
      %end;

%put End macro split_macrovalue;
%mend split_macrovalue;


These macro calls below take the macro variable ‘gender’ with a value list and populate them into a series of macro variables with a prefix ‘gen’…Please note the variations of the delimiters in each of the macro invocations.
 
options mprint mprintnest mlogic mlogicnest;

%let gender = 'F','M';
%split_macrovalue(gender,gen,cnt,dlm=comma,printvalue=Y);

%let gender = 'F'|'M';
%split_macrovalue(gender,sgen,scnt,dlm=pipe,printvalue=Y);

%let gender = 'F' 'M';
%split_macrovalue(gender,tgen,tcnt,dlm=space,printvalue=Y);


I hope these macros help you in simplifying your situations ….


Please let me know if you have any questions.

Jul 14, 2013

Develop your own SAS Functions (user-written) in v9.1+ using Proc FCMP

Have you ever wondered, Why SAS never had functions similar to any other programming Language i.e. C, C++, Java…
LINK/ Return statement and SAS Macros to some extent served the purpose in modularizing and developing re-usable code for repeating tasks…but doesn’nt make it is easy to follow….Macros are easier to reuse; however, they are not independent from the main program, they involve non-DATA step syntax, and substantial use of macros can result in illegible code.
SAS finally broke this jinx with FCMP procedure in version 9.1 and above.
In SAS®9.1, the FCMP procedure provides the ability to write functions to be used in conjunction with few SAS Procedures….

Starting with SAS® 9.2, these user-written functions can be called from a DATA step as well.PROC FCMP provides the ability to write true functions and CALL routines in DATA step syntax that are stored in a data set. In SAS 9.2, FCMP routines can be called from the DATA step like any other SAS function. This enables programmers to more easily read, write, and maintain complex code with independent and reusable subroutines.
Here are some examples of How to Use them…
NOTE: These Examples below work with SAS v9.2 ONLY.
Using Numeric Data in the FUNCTION Statement
The following example uses numeric data as input to the FUNCTION statement of PROC FCMP:
Using Numeric Data in the FUNCTION Statement
The following example uses numeric data as input to the FUNCTION statement of PROC FCMP:
proc fcmp;
   function inverse(in);
      if in=0 then inv=.;
      else inv=1/in;
      return(inv);
   endsub;
run;
 
data invert;
input x;
y=inverse(x);
cards;
10
20
30
;
run;
Using Character Data in the FUNCTION Statement
The following example uses character data as input to the FUNCTION statement of PROC FCMP. The output from FUNCTION test is assigned a length of 12 bytes.
proc fcmp outlib=work.funcs.math;
   function test(x $) $ 12;
   if x = 'yes' then
      return('si si si');
      else
      return('no');
   endsub;
run;
 
data _null_;
   spanish=test('yes');
   put spanish=;
run;
Using Variable Arguments with an Array
The following example shows an array that accepts variable arguments. The example implies that the summation function can be called as follows: sum = summation(1, 2, 3, 4, 5); .
proc fcmp outlib=work.funcs.math;
function summation (b[*]) varargs;
   total = 0;
   do i = 1 to dim(b);
       total = total + b[i];
   end;
return(total);
endsub;
 
data summate;
 array x(*) x1-x3 {10,20,30};
 summ=summation(x);
run;
Directory Traversal(v 9.2 ONLY)

Refer to this Paper for Detailed Explaination of a sample code

Example Codes