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

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.

 

1 ACCEPTED SOLUTION

Accepted Solutions
ballardw
Super User

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.

View solution in original post

12 REPLIES 12
ChrisNZ
Tourmaline | Level 20

So the macro variable &sizeit is now '10'. 

 

Do you actually have quotes in the value of the macro variable? Remove them.

 

Astounding
PROC Star

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.

Kow
Obsidian | Level 7 Kow
Obsidian | Level 7

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 ?

 

 

 

 

 

 

 

 

Kow
Obsidian | Level 7 Kow
Obsidian | Level 7

Here is a log file of code and log messages, if it works.

 

 

 

ChrisNZ
Tourmaline | Level 20

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?

Reeza
Super User
You haven't provided enough information to debug or replicate your issue. I'm going to make a wild guess that this part of the code is in a macro and part is not and you're running into variable scoping issues. Look at CALL SYMPUTX() and global scoping.
FreelanceReinh
Jade | Level 19

@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.

 

ballardw
Super User

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.

Astounding
PROC Star

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.

Kow
Obsidian | Level 7 Kow
Obsidian | Level 7

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?

 

 

 

 

 

ballardw
Super User

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.

 

ChrisNZ
Tourmaline | Level 20

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: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

How to Concatenate Values

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 12 replies
  • 2212 views
  • 2 likes
  • 6 in conversation