6
votes

Is there a shorthand in SAS for defining a sequence of letters in an array?

Many languages possess a mechanism for doing so easily and I imagine SAS does too, although I'm unable to find a reference for it.

For instance, in R I could do

> x <- letters[1:4]
> x
[1] "a" "b" "c" "d"

In Python, one way is

>>> import string
>>> list(string.ascii_lowercase[:4])
['a', 'b', 'c', 'd']

In SAS, I currently am having to list the letters explicitly,

data _null_;
  array letters (4) $ _temporary_ ('a', 'b', 'c', 'd');
  do i = 1 to hbound(letters);
    put letters(i);
  end;
run;
4

4 Answers

4
votes

You can use the COLLATE() to generate a string of single byte characters. If you don't know the ASCII code for the start of the block of characters you want then use the RANK() function.

So if you only want four characters start from 'a' you could do it this way.

  length str $4 ;
  str = collate(rank('a'));

Or you could also use the optional second parameter to COLLATE() to specify how many characters you want.

  length str $4 ;
  str = collate(rank('a'),rank('a')+vlength(str)-1);

There is no need for an "array", just use a variable.

data _null_;
  length str $4 ;
  str = collate(rank('a'));
  do i=1 to vlength(str);
    ch = char(str,i);
    put i= ch= :$quote. ;
  end;
run;

Result:

i=1 ch="a"
i=2 ch="b"
i=3 ch="c"
i=4 ch="d"
4
votes

Not that I'm aware of, but it is trivial to write a macro to do that.

%macro letter_sequence(start=1,end=, lower=1);
  %local i addon;
  %if &lower=1 %then %let addon=96;
  %else %let addon=64;
  %do i = &start+&addon. %to &end.+&addon.;
    "%sysfunc(byte(&i.))"
  %end;
%mend letter_sequence;

data test;
  array x[4] $ (%letter_sequence(end=4));
  put x[2]=;
run;
3
votes

Another option is to use the collate function and the call pokelong routine:

/*Upper case*/
data _null_;
  array a[26] $1;
  call pokelong(collate(65,65+25),addrlong(a1),26);
  put _All_;
run;

/*Lower case*/
data _null_;
  array a[26] $1;
  call pokelong(collate(97,97+25),addrlong(a1),26);
  put _All_;
run;

This bypasses all the usual mechanisms for assigning values for individual variables and takes advantage of the default memory layout used by SAS for character arrays, copying the whole alphabet in one go starting at the address for the first element.

N.B. call pokelong might not be available in some locked-down SAS environments, e.g. SAS University Edition. Also, this might not work properly with temporary arrays in SAS 9.1.3 or earlier on some platforms.

I think this is the only way to do this in SAS without either hard-coding your letters or writing some sort of loop.

0
votes

You can use a combination of the rank function (which converts a character to its ascii value) and the byte function (which converts back the other way).

data _null_;
length seq $51; /* define seq as character variable */
do i = rank('a') to rank('d'); /* loop through ascii values of required letters */
call catx(' ',seq,byte(i)); /* concatenate letters */
end;
put seq; /* print final output */
run;