I am fairly new to SAS and I am struggling to understand how to write programs in the SAS macro language that are data driven. However, proc lua makes sense to me. Nonetheless, I would like to know both.
The code below--silly as it may be--illustrates the concepts that I am struggling with. It makes a random list of cat names, and then finds out which cats have been naughty and which have been nice. It then prints out a Christmas list, which lets me know which cats should buy presents for and how much I can spend on each of them.
The parts of the code that I am having difficulties translating/implementing into the SAS macro language are:
1) The section that figures out the suffix for the jth cat, and then prints it to the log. How can you change the values of macro variables on the fly and then use them within a macro loop to write something to the log? Is there a way to use 'call symput' or 'symget' in a macro?
2) How can you write to multiple datasets while in a macro loop, similar to what I have done below.
3) How can you call custom functions compiled with proc fcmp in a sas macro to control the flow of the macro.
* This macro create a list of cat names;
%macro getsomecats(num);
%local mycat;
%let mycat = cat1;
%do j = 2 %to #
%let mycat = &mycat.%str( cat)&j.;
%end;
&mycat
%mend;
* SAS macro that duplicates the Excel RANDBETWEEN function. Taken from
http://blogs.sas.com/content/iml/2015/10/05/random-integers-sas.html;
%macro RandBetween(min, max);
(&min + floor((1+&max-&min)*rand("uniform")))
%mend;
* Get the number of cats that will be in our list;
data _null_;
seed = %randbetween(1,50);
call symputx('myseed',seed);
run;
* Make a random list of cat names;
%let morecats = %getsomecats(&myseed.);
* Reference some custom functions compiled with proc fcmp;
options cmplib=(MY_FUNCS.PURE_MATH);
libname NUMBERS '/folders/myfolders';
* Make two data sets: one for all of my cats, and another for
the cats that I should by Christmas presents;
proc lua;
submit;
-- Import Lua libraries
require 'string'
require 'math'
-- If the tables I want to create exist, then delete them.
if sas.exists('my_cats') then
sas.submit([[
proc delete data=my_cats;
]])
print('my_cats deleted')
end
if sas.exists('xmas_list') then
sas.submit([[
proc delete data=xmas_list;
]])
print('xmas_list deleted')
end
-- Set up some data sets
sas.new_table('my_cats', {
{name='Name', type='C', length=8},
{name='Status', type='C', length=8},
{name='Gender', type='C', length=6}
})
sas.new_table('xmas_list', {
{name='Name', type='C', length=8},
{name='Status', type='C', length=8},
{name='Gender', type='C', length=6},
{name='Budget', type='N', length=8}
})
-- Create data set handels for our new data set
local dsh1 = sas.open('my_cats', 'u')
local dsh2 = sas.open('xmas_list', 'u')
-- Declare some useful variables
local suffix, status, gender, name
local ub = 1 -- upper bound for 'for' loop
local mystr = sas.symget("morecats")
-- Find out upper bound on number of cats
for j = 1, string.len(mystr) do
if mystr:sub(j,j) == ' ' then ub = ub + 1 end
end
mystr = nil -- we do not need mystr anymore
print('Making my christmas list:') -- Write header in log
for j = 1, ub do
-- Create a suffix for jth cat; I am very confused about
-- how to do this in the SAS macro language.
if j % 10 == 1 and j % 100 ~= 11 then suffix = 'st'
elseif j % 10 == 2 and j % 100 ~= 12 then suffix = 'nd'
elseif j % 10 == 3 and j % 100 ~= 13 then suffix = 'rd'
else suffix = 'th' end
-- Find out if the jth cat has been naughty or nice.
-- 'isprime' is a custom function compiled with proc fcmp,
-- it returns 1 if a number is prime and 0 if it is composite.
if sas.isprime(j) == 1 then
status = 'naughty'
else
status = 'nice'
end
-- Assign the cat a gender randomly. I would like to
-- know how to this in the SAS macro language, including
-- how to use a list so that I can reference the two different
-- charchteristics of gender.
if sas.ranuni(0) < .5 then
gender = {'male', 'he'}
else
gender = {'female', 'she'}
end
-- Get the cats name; scan the macro variable
-- 'morecats' for the jth entry.
name =sas.scan(sas.symget("morecats"),j)
-- Write information in our log about this cat,
-- again, I cannot figure out how to deal with the
-- suffix part here.
print('My '..j..suffix.." cat's name is "..name..
', and '..gender[2]..' is usually '..status)
-- Add the jth cat to my data set of cats
sas.append(dsh1)
sas.put_value(dsh1,"Name", name)
sas.put_value(dsh1,"Status", status)
sas.put_value(dsh1,"Gender", gender[1])
sas.update(dsh1)
-- If the jth cat is usually nice then, add him or her
-- to the data set of cats that need to by Christmas
-- presents for.
if status == 'nice' then
local budget = 10 * sas.phi(math.random(30))
sas.append(dsh2)
sas.put_value(dsh2,"Name", name)
sas.put_value(dsh2,"Status", status)
sas.put_value(dsh2,"Gender", gender[1])
sas.put_value(dsh2,"Budget", budget)
sas.update(dsh2)
end
end
sas.close(dsh1)
sas.close(dsh2)
endsubmit;
run;
proc print data=xmas_list;
var _all_;
sum Budget;
run;
Example output:
Example log:
Making my christmas list:
My 1st cat's name is cat1, and she is usually nice
My 2nd cat's name is cat2, and he is usually naughty
My 3rd cat's name is cat3, and she is usually naughty
My 4th cat's name is cat4, and she is usually nice
My 5th cat's name is cat5, and she is usually naughty
My 6th cat's name is cat6, and he is usually nice
My 7th cat's name is cat7, and she is usually naughty
My 8th cat's name is cat8, and she is usually nice