0
votes

I'd like to create a function that uses hash. The table that is being hashed has 3 columns: Age, Sex, a. I'd like to use a macro in the following way:

  1. Define macro before data step:

    %macro hashfind(age, sex) ;
    rc=tab.find(key: &age, key: &sex );
    %LET p=a ;
    %PUT p;
    %mend;
    
  2. Open data step, Define hash as following:

    if _n_=1 then
            do;
                declare hash tab();
                rc=tab.definekey('Age');
                rc=tab.definekey('Sex');
                rc=tab.definedata('a');
                rc=tab.definedone();
    
                do until (eof1);
                    set work.tab end=eof1;
                    rc=tab.add();
                    put rc;
                end;
    end;
    
  3. Use the macro in data step in the following way:

  4. abc=%hashfind(30, 'M') ;
    

this way the "abc" value is always equal 1. That's not correct with the table. However after I execute the macro and assign this value outside of macro abc=a which is correct value.

To sum it up: what can I do to use whole hash inside macro? (I will extend the macro in the future so it's a necessity.)

Or: Does anyone know how to define a function, that uses hashes in the way I'd like? Using PROC FCMP is not an option, because hashing in PROC FCMP defined functions is not available in SAS 7.1 which I'm using.

2
Your SAS version cannot be correct, that's probably your EG version? Use %put &sysver.; to see your SAS version in the log.Reeza
I'm a bit confused by the %let statement and %put statement in your macro. Can you explain the purpose of these?Quentin

2 Answers

1
votes

If you call your macro like %hashfind(30,'M') rather than abc=%hashfind(30,'M'); it should work.

When you call it the second way, your SAS DATA step code becomes abc=rc=tab.find(key: 30, key: 'M'); That is valid code, and will assign 1 as the value of abc because rc probably has a value of 1 from add() and the find() returns 1 (assuming the key is found).

If you want to specify the name of the data step variable to hold the return code, in this simple case you can change your macro definition to be:

%macro hashfind(age, sex) ;
tab.find(key: &age, key: &sex )
%mend;

I removed the rc= and the semicolon at the end. That makes it more function-like. You could then call as abc=%hashfind(30,'M');

I skipped over discussing your macro %let and %put statements, because I'm not sure what you are trying to do with them.

0
votes

I created this macro to make the code a bit more user friendly. The way it's written only puts the found variables in the log but it should be fairly easy to modify that.

The macro has 4 arguments: the key(s), the variable you want to find, the input data set, and the value you want to find.

%macro hashfind(byvars, findvars, inset, find);

%let data_key = %trim(&byvars);
%let data_key = %sysfunc(tranwrd(&data_key,%str( ), %str(",")));
%let findvars = %trim(&findvars);

data _NULL_;
if 0 then set &inset;

if _N_ = 1 then do;
   declare hash tab(dataset: "&inset.");

   rc = tab.DefineKey  ("&data_key.");
   rc = tab.DefineData ("&findvars.");
   rc = tab.DefineDone ();
end;

&byvars = "&find.";
rc = tab.find();
put &findvars=;

run;

%mend;

The macro can then be called as follows:

%hashfind(key1 key2 key3 etc, var, dataset, value);

This should probably get you a good start, hope it helps.