6

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;
Lorem Ipsum
  • 4,020
  • 4
  • 41
  • 67

4 Answers4

4

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;
Joe
  • 62,789
  • 6
  • 49
  • 67
4

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"
Tom
  • 47,574
  • 2
  • 16
  • 29
  • Interesting! Are you able to explain the `:quote.`? I see that it places quotes around the value of `ch`. Is it a format? Is the colon part of the expression or is it the multifaceted colon-operator? – Lorem Ipsum Jul 20 '17 at 17:31
  • That is just to add the quotes in the output to make it clearer what values are actually in the variable. It should be `:$quote.` since it is a character variable. The `:` will cause it to trim the values and quote, which is actually probably not needed for this case but I just included out of habit. – Tom Jul 20 '17 at 18:06
3

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.

user667489
  • 9,501
  • 2
  • 24
  • 35
0

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;
Longfish
  • 7,582
  • 13
  • 19