BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
xueke47
Fluorite | Level 6

Hi all,

 

I'm a new SAS programmer with some Python background. I had thought SAS is a procedural language only capable of dealing with tabular data, until I recently discovered proc fcmp and had a better understanding of the data step.

 

In summary, what I realized is that whatever code we put within a data step is to some degree similar to a single script in a general-purpose programming language (e.g. Python)––we define certain variables in memory and performs operations on them. If only using the data step, the feature of variable scoping is missing, but proc fcmp conveniently fills that gap. Then I come up with the question in the title–can we declare a hash object in a data step and pass it to a function/subroutine defined via proc fmcp by reference?

 

To clarify my question, I know we can pass array by reference as in the following code.

 

proc fcmp outlib=work.funcs.trial;
subroutine modify(a[*]);
outargs a;
n=dim(a);
do i=1 to n;
a[i]=a[i]*2;
end;
endsub;
quit;
 
options cmplib=work.funcs;
 
data test;
array a[2];
a[1]=1; a[2]=2; output;
call modify(a); output;
run;
 
The array is defined in the data step and passed to the subroutine modify() to be modified. Can we replace the array statement by a hash object declaration and in some way pass it to a subroutine to be modified?
 
The reason I'm asking is that I feel SAS array and hash object are in some sense similar to Python list and dictionary. If my question has a positive answer, then basically we have two very important data structures in SAS and can replicate a lot of algorithms that have been implemented in general-purpose programming languages. What I specifically have in mind is to define a recursive function by proc fcmp and call it in a data step to perform a decision tree traversal. The underlying question is to determine if two CBSAs within a state can be connected by a chain of adjacent rural counties. The problem certainly has other solutions, but I'm just wondering whether it can be done this way, since I think the question itself is recursive in nature. 
 
Thanks!
 
Ke
1 ACCEPTED SOLUTION

Accepted Solutions
RichardDeVen
Barite | Level 11

No.

 

You can not pass a DATA Step instantiated hash component object to an FCMP user defined function or call routine.

 

However, you can pass a HASH object instantiated in FCMP to a FCMP user defined function or call routine using the argument type specifier HASH.  Note:  This information is not mentioned in the documentation FCMP Procedure: FUNCTION statement.  The earlier referenced paper  "129-2013: Hashing in PROC FCMP to Enhance Your Productivity (sas.com)" Andrew Henrick, Donald Erdman, and Stacey Christian, SAS Institute Inc., Cary, NC, is from SGF 2013 and does indicate arguments can be followed by type specifier HASH

 

argument

specifies one or more arguments for the function. You specify character arguments by placing a dollar sign ($) after the argument name. In the following example,function myfunct(arg1, arg2 $, arg3, arg4 $);arg1 and arg3 are numeric arguments, and arg2 and arg4 are character arguments.

Example Code:

 

Hash created in DATA Step can not be passed to FCMP.

 

proc fcmp outlib=work.hash.sandbox;
  function lumberjack(eaters HASH);

    put 'hi';

    return (0);
  endsub;
run;

options cmplib=work.hash;

data _null_;
  attrib name length=$20 age height weight length=8;

  call missing (of name--weight);

  declare hash students(dataset:'sashelp.class');
  students.defineKey('name');
  students.defineData('name', 'age', 'height', 'weight');
  students.defineDone();

  rc = lumberjack(students);
run;

--- LOGS ---

NOTE: Invalid type conversion.

A FCMP instantiated HASH can be passed to a FCMP function.  NOTE: A PUT statement in FCMP will write to ODS LISTING (and not LOG window as one might expect from DATA Step experiences)

proc fcmp;
  attrib name length=$20 age height weight length=8;

  function lumberjack(eats hash);
    return (eats.num_items());
  endsub;

  declare hash students(dataset:'sashelp.class');
  rc = students.defineKey('name');
  rc = students.defineData('name', 'age', 'height', 'weight');
  rc = students.defineDone();

  count = lumberjack(students);

  put 'count returned from lumberjack =' count;
run;
quit;

dm 'listing';

--- Shows list in OUTPUT window ---

The FCMP Procedure

count returned from lumberjack = 19

 

View solution in original post

6 REPLIES 6
PeterClemmensen
Tourmaline | Level 20

There is an example using a hash object as argument to a FCMP Function in the article Hashing in PROC FCMP to Enhance Your Productivity.

yabwon
Onyx | Level 15

Hi,

 

As far as I know you can't pass hash object as FCMP function argument.

But recursion is available in FCMP functions.

 

Arrays and Hashtables may look similar to Python Lists and Dictionaries, but they are different in some fundamental ideas you have to be aware of:

0) in SAS declaration of an Array is in compilation phase, Hash tables are from execution phase, in Python there is no such differentiation,

1) data step Arrays are not dynamically "resizeable"(you can add new elements during execution) as Lists are (in the FCMP only the numeric arrays are "resizeable", Hash tables are "resizeable" too),

2) Lists are pointing to objects in memory while Arrays (the temporary one) reserve some fixed part of memory for data,

3) Arrays ale only one type (num or char) and Lists can "contain" objects of different type,

4) Dictionaries can have only one data portion to one key, Hash tables can have multiple data portions to 1 key,

5) Data portion of Hash table can have multiple elements, but they are fixed types, in Dictionary you can have "anything" for keys and "anything" for data.

 

 

All the best

Bart

_______________
Polish SAS Users Group: www.polsug.com and communities.sas.com/polsug

"SAS Packages: the way to share" at SGF2020 Proceedings (the latest version), GitHub Repository, and YouTube Video.
Hands-on-Workshop: "Share your code with SAS Packages"
"My First SAS Package: A How-To" at SGF2021 Proceedings

SAS Ballot Ideas: one: SPF in SAS, two, and three
SAS Documentation



xueke47
Fluorite | Level 6
Thanks Bart! Python list and dictionary are really flexible. I suppose if I want to implement the same thing in SAS I have to plan the data representation and variable declarations very carefully (makes me recall my C programming experience a long time ago), but having array and hash object that can be passed by reference is still better than not having it.
RichardDeVen
Barite | Level 11

No.

 

You can not pass a DATA Step instantiated hash component object to an FCMP user defined function or call routine.

 

However, you can pass a HASH object instantiated in FCMP to a FCMP user defined function or call routine using the argument type specifier HASH.  Note:  This information is not mentioned in the documentation FCMP Procedure: FUNCTION statement.  The earlier referenced paper  "129-2013: Hashing in PROC FCMP to Enhance Your Productivity (sas.com)" Andrew Henrick, Donald Erdman, and Stacey Christian, SAS Institute Inc., Cary, NC, is from SGF 2013 and does indicate arguments can be followed by type specifier HASH

 

argument

specifies one or more arguments for the function. You specify character arguments by placing a dollar sign ($) after the argument name. In the following example,function myfunct(arg1, arg2 $, arg3, arg4 $);arg1 and arg3 are numeric arguments, and arg2 and arg4 are character arguments.

Example Code:

 

Hash created in DATA Step can not be passed to FCMP.

 

proc fcmp outlib=work.hash.sandbox;
  function lumberjack(eaters HASH);

    put 'hi';

    return (0);
  endsub;
run;

options cmplib=work.hash;

data _null_;
  attrib name length=$20 age height weight length=8;

  call missing (of name--weight);

  declare hash students(dataset:'sashelp.class');
  students.defineKey('name');
  students.defineData('name', 'age', 'height', 'weight');
  students.defineDone();

  rc = lumberjack(students);
run;

--- LOGS ---

NOTE: Invalid type conversion.

A FCMP instantiated HASH can be passed to a FCMP function.  NOTE: A PUT statement in FCMP will write to ODS LISTING (and not LOG window as one might expect from DATA Step experiences)

proc fcmp;
  attrib name length=$20 age height weight length=8;

  function lumberjack(eats hash);
    return (eats.num_items());
  endsub;

  declare hash students(dataset:'sashelp.class');
  rc = students.defineKey('name');
  rc = students.defineData('name', 'age', 'height', 'weight');
  rc = students.defineDone();

  count = lumberjack(students);

  put 'count returned from lumberjack =' count;
run;
quit;

dm 'listing';

--- Shows list in OUTPUT window ---

The FCMP Procedure

count returned from lumberjack = 19

 

xueke47
Fluorite | Level 6

Thank you so much Richard!

 

Is it reasonable to compare the proc fcmp in your second snippet to a Python script? When the procedure is run, it feels very much like running a Python script. Without the outlib= option, the lumberjack function can only be called in the same proc fcmp, while in Python, a function defined within one script cannot be called in another script unless first imported. The two languages are certainly differently, but this analogy helps me connect SAS to my previous programming experience.

 

I also have a question about variable scoping in proc fcmp. In a Python script, if a variable is defined outside any function then it is a global variable and its value can be referenced inside any function with no need of declaration. In proc fcmp, it looks like the only way to use a variable declared outside a function is to pass it as an argument, and declare "outargs" if we want to modify its value. Is this the correct understanding?

 

Finally, is it possible to output the content of a hash object instantiated in proc fcmp by the output method? 

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

Register now!

What is Bayesian Analysis?

Learn the difference between classical and Bayesian statistical approaches and see a few PROC examples to perform Bayesian analysis in this video.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 6 replies
  • 905 views
  • 6 likes
  • 4 in conversation