Using macro variable to create names for variables

Mean Joe

TS Contributor
#1
I want to make a string variable with a number of 0's (say 842 for example).
This works:
Code:
*Macro to make a string var of specified length;
%macro zerofill(strname, strlength);
length &strname $100.;
%let strtemp=%eval(&strlength);
%do %while (&strtemp>0);
substr(&strname, &strtemp, 1)="0";
%let strtemp=%eval(&strtemp-1);
%end;
%mend zerofill;
I worry about the space for a variable of length 842 (should I?), so I decide to split the variable into parts that are length 100. So if I want 842 zeroes, then I decide I should make 9 variables
part0 = 000...000 (100 zeroes)
part1 = 000...000 (100 zeroes)
part2 = 000...000 (100 zeroes)
etc
part8 = 000...000 (42 zeroes)

On the other hand, if I want a variable with 2097 zeroes, then I will need 21 variables. Thus, the problem I'm facing is that I need to be flexible in the variables part# that I create. I figure one way to go about this is using a macro variable &n1 and letting it run from 0 to {number of variables-1}, but I don't know how to assign &n1--I tried using call symput() but am having trouble.

I tried this:
Code:
%macro wrong(bignumber);
data init;
	_init=%eval(&bignumber);
	_init_head=int(_init/100);
	_init_tail=mod(_init,100);
	_i=0;
	do while (_i < _init_head);
		call symput("n1", compress(_i));
		%zerofill(part&n1,100);
		_i = _i + 1;
	end;
	call symput("n1", compress(_init_head));
	%zerofill(part&n1,_init_tail);
run;
%mend;
I get this warning

WARNING: Apparent symbolic reference N1 not resolved.


Flummoxed because if I put %put _user_; inside the macro, and drop the %zerofill statements, then I see that &n1 is getting assigned. But when I try to reference part&n1 something is wrong.
I have two requests that I think can be answered:
1) What can I do to fix my code? There must be some way to do this, using %NRSTR or something like that?

and/or 2) Do you have another suggestion to do what I want?

I can get by for now by just setting my limit to 100 parts, but I'd like to know what's going wrong.
 

Mean Joe

TS Contributor
#3
Hi Link

I don't have a data set. I just wanted to make a variable with hundreds of zeroes. Hope this doesn't sound too crazy of a desire.

The zerofill macro indeed needs to be called in a data step:
data test;
%zerofill(mystring,100);
run;

The other macro (elegantly named "wrong" above) creates a dataset init by itself. Basically I wanted the macro to write code:
data init;
%zerofill(part0,100);
%zerofill(part1,100);
%zerofill(part2,100);
*etc;
%zerofill(part9,42);
run;

After I have my zeroes, I can do whatever I want. I don't need the variables _init, _init_head, init_tail...just the variables part0-part9/part21/whatever.
 

Link

Ninja say what!?!
#4
ok. So to make sure I have this right, you want a macro that will create a string using no previous values. If you type up:

data test;
%zerofill(mystring,100);
run;

Then "mystring" would just be a string typed into the macro (that becomes the variable name), and "100" would be the number of 0's you want in the string. In addition, you want this macro to create separate variables for each set of 100 0's.

So if you type up:

data test;
%zerofill(mystring,842);
run;

Then the variables "mystring0", "mystring1", ..., "mystring8" would be created, and variables 0-7 would each have a length of 100 (and 100 0's) and variable8 would have a length of 42 (and 42 0's).

Is that correct?
 
Last edited:

Link

Ninja say what!?!
#5
Here you go. I've tested it out too and it seems to be giving me no problems.

Code:
%macro zerofill(strname, strlength);
	%if &strlength <= 100 %then %do;
		length &strname $%eval(&strlength).;
		%let strtemp=%eval(&strlength);
		%do %while (&strtemp>0);
			substr(&strname, &strtemp, 1)="0";
			%let strtemp=%eval(&strtemp-1);
		%end;
	%end;
	%if &strlength > 100 %then %do;
	%local n_parts;
	%let n_parts = %eval(&strlength/100);
		%do i=0 %to &n_parts;
			%if &i < &n_parts %then %do;
				length &strname&i $%eval(100).;
				%let strtemp=100;
				%do %while (&strtemp>0);
					substr(&strname&i, &strtemp, 1)="0";
					%let strtemp=%eval(&strtemp-1);
				%end;
			%end;
			%if &i = &n_parts %then %do;
				length &strname&i $%eval(&strlength - (&i*100)).;
				%let strtemp=%eval(&strlength - (&i*100));
				%do %while (&strtemp>0);
					substr(&strname&i, &strtemp, 1)="0";
					%let strtemp=%eval(&strtemp-1);
				%end;
			%end;
		%end;
	%end;
%mend zerofill;
 

Link

Ninja say what!?!
#6
Note: If you run the command:

data test;
%zerofill(mystring,842);
run;

without any previous values in the dataset, you'll have to type in "output;" as well. This will force SAS to output the variables it is creating into the empty dataset.
 

Mean Joe

TS Contributor
#7
First, thanks Link for the code. I'll be using that.

Second, I'm wondering why call symput is not working the way I thought it would work. I thought call symput("n1", compress(_i)); would basically be storing a variable character string in "macro variable" &n1. So by using &n1, the variable character string would be pasted in its place.

Here's one example of me using call symput that works like that (but evidently something is different):
Code:
data wholeset;
input id $ income numkids apartment age;
datalines;
S01 24 2 234 45
S02 892 4 289 49
S03 32 8 298 41
S04 38942 7 135 37
S05 9 6 232 35
S06 398 5 189 42
S07 982 4 197 58
S08 348 3 200 92
S09 899 2 122 18
S10 98 1 212 21
;
run;
*The subjects are good, but I want to drop some variables;

data badvars;
input id $;
datalines;
income
apartment
;
run;

data _null_;
set badvars;
retain n 1;
call symput("badvar"||left(n),compress(id));
call symput("badvar_count",n);
n=n+1;
run;

%put _user_;

%macro badvar_dropper;
%if (%eval(&badvar_count)>=1) %then %do;
	drop 
	%do i=1 %to &badvar_count;
		&&badvar&i
	%end;
	;
%end;
%mend badvar_dropper;

data prunedset;
	set wholeset;
	%badvar_dropper;
run;
So there I use call symput to drop a varying number of variables (however many are listed in badvars data step).

Is it because the scope in which I use call symput is different? In this example I'm using call symput in a data step, whereas in my 842 character variable code I was using call symput inside of a macro, and outside the macro those macro variables do not exist. But inside the macro, they do exist, and when I tried to reference them I could not do it simply. Looking for info on how I can reference them.