I am running a program where I analyze text character frequency for compression (Huffman coding)
I determine the array size needed for analysis and pass that value to a macro variable. I need to set my array size based on the macro variable.
Let the array size needed be 10. So the macro variable &sizeit is now '10'. I use symput to pass this value and confirm it is resolving as expected.
I need to do something like this:
data ;
set treefreqs ;
retain count_1 - count_&sizeit ;
array countree [*] count_1 - count_&sizeit ;
I am declaring the new array and setting it with existing values from the treefreq data -- the values for count1 - count10 are already defined.
I keep failing on getting the macro variable reference to resolve as needed i.e 'retain count_1 - count_10' and the array does not resolve count_1 - count_&sizeit correctly either.
I know the macro is "text" not numeric, but why does this fail?
I have tried using periods to resolve the macro i.e count_.&sizeit but that fails as well.
I don't see an easy reference to this question, though it seems to me I have dealt with it.
Any suggestions appreciated.
For a large economy sized hint you might want to read the documentation and specifically the differences for
CALL SYMPUT
and
CALL SYMPUTX
Short: Use Call symputx in your specific case and I bet the issue goes away.
So the macro variable &sizeit is now '10'.
Do you actually have quotes in the value of the macro variable? Remove them.
Inspect the value by adding this before the DATA step:
%put *&sizeit*;
That will spell out any one of a number of problems. It might be the quotes as was mentioned, but it also might be leading blanks, the easy solution to remove leading blanks being:
%let sizeit = &sizeit;
But until you see what is in the macro variable exactly, it's difficult to diagnose.
Ok, the quotes around the 10 were simply to indicate I knew the macro is text, not a literal numeric.
The macro variable does resolve correctly.
Sorry, cutting and pasting both code and results is ridiculous with SAS University, I have tried to attach a code, log and results as a file below (failed I guess). There is a lot of stuff there, my question is limited to definition of the array size.
data size ;
set treefreq end=eof ;
if eof = 1 then do ;
call symput("SIZE_NEEDED",_N_) ;
output ;
end ;
proc print ;
title "Size Needed is &size_needed" ;
That works perfectly and &size_needed prints correctly as 11 (the correct value).
This is my question on immediately following code:
data two ;
set treefreq ;
array countree {*} count_1 - count_&size_needed ; ***<<<this fails immediately****;
run ;
The error I get in the log is:
ERROR: MISSING NUMERIC SUFFIX ON NUMBERED VARIABLE LIST (count_1 - count_ )
I figure because text does not resolve as numeric. Like I said I tried a couple of things -- putting in periods to get resolution but nothing worked. I am not referencing the array correctly in some way.
How do I use a macro variable to reference an array element ?
Here is a log file of code and log messages, if it works.
What @FreelanceReinh said.
And if you had run
%put *&sizeit*;
as @Astounding asked, you'd have seen the left padding.
Please try to follow the replies when you ask questions. Otherwise why bother?
@Kow wrote:
The macro variable does resolve correctly.
(...)
title "Size Needed is &size_needed" ;
That works perfectly and &size_needed prints correctly as 11 (the correct value).
I assume you checked this in HTML output where multiple blanks are compressed. In the listing destination, however, the title would have looked like this:
Size Needed is 11
You may have noticed the numeric-to-character-conversion note in the log (from your data step):
NOTE: Numeric values have been converted to character values at the places given by: (Line):(Column).
CALL SYMPUT used the default format BEST12. for the conversion of _N_=11 to a character value (to be stored in macro variable SIZE_NEEDED). The result is a right-aligned string of length 12 consisting of 10 blanks and two 1s: " 11" (without quotation marks). As a consequence, count_&size_needed resolved to count_ 11, leading to the "missing numeric suffix" error for obvious reasons.
Astounding has already provided a solution: the %PUT statement for diagnosis -- the leading blanks would have shown after the first asterisk -- and the %LET statement as a means of removing the leading blanks.
An alternative solution is to use CALL SYMPUTX in place of CALL SYMPUT. It removes the leading blanks automatically and doesn't produce the conversion note in the log.
For a large economy sized hint you might want to read the documentation and specifically the differences for
CALL SYMPUT
and
CALL SYMPUTX
Short: Use Call symputx in your specific case and I bet the issue goes away.
Don't push too hard on CALL SYMPUT vs CALL SYMPUTX. Sometimes a macro variable gets created by PROC SQL, using INTO : (which would face the same issue of numeric-to-character conversion and leading blanks). In this particular program, adding the "X" would help.
Using SYMPUTX to define the macro variable worked and eliminated the problem. Thanks to all for the assistance.
Once I used SYMPUTX the array statement : ARRAY [*] COUNT1 - COUNT&SIZE_NEEDED resolved and ran.
The problem as described above is that SYMPUT retains the leading blanks on the macro variable and pads them into the resolved reference.
i.e %LET SIZE_NEEDED = 11 ;
%PUT "SIZE NEEDED:" &SIZE_NEEDED
resolves in the log to : SIZE NEEDED: ' 11' with multiple blank spaces preceding the 11. That prevents correct resolution in later calls to the macro variable.
This does answer my question but further questions arise :
-I note printing the macro var in a TITLE statement WILL strip the leading blanks and the padding will not be shown. If it strips them here it may also do so in other places without explicitly noting that.
How the length of the macro variable is determined is an additional question. "The length of a macro variable is determined by the text assigned to it instead of a specific length declaration. So its length varies with each value it contains." http://support.sas.com/documentation/cdl/en/mcrolref/61885/HTML/default/viewer.htm#a002293823.htm
That doesn't appear to be the case here -- assigning a numeric to a macro var using SYMPUT results in a length of 8 bytes regardless of the text. Passing the number 8 results in the same length macro variable as 100,000. I assume this is from using SYMPUT somehow.
I also don't understand why the printed value in the log shows such a large number of blank spaces, many more than 8, for the resolved reference as put to the log?
Default conversion of numerics to character (almost any time you do not explicitly state a PUT) uses 8 as the length.
Much of the output generated by procedures will trim the leading blanks:
data example; x=' something'; run; proc print; run;
for instance. Which why we have a STYLE option ASIS to modify that behavior in some places.
1- I also don't understand why the printed value in the log shows such a large number of blank spaces, many more than 8, for the resolved reference as put to the log?
The default format used when not specified is best12. which results in a length of 12. It's a poor format to use really, but that's what we get by default. Not too sure why a length of 8 is mentioned.
You can see it by using
data T;
call symput('a',1);
run;
%put &=a*;
which results in
A= 1*
123456789012
Length is 12 as you can see.
2- Now that SYMPUTX exists, there is no reason to use SYMPUT.
3- The code above generates
NOTE: Numeric values have been converted to character values at the places given by:
Do not tolerate these messages in the LOG.
If you accept them for valid data, you will miss when they highlight invalid data and this will bite you hard.
Your LOG must be squeaky clean (as much as possible, SAS can make this hard to achieve)
4- I note printing the macro var in a TITLE statement WILL strip the leading blanks
Some reporting formats, such as HTML, do not show multiple spaces. If you go see the HTML source, all the spaces are here, but they are compressed for display.
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.