Even so, I like the approach of the RANK function -- which we don't often see. Converting the char to its ASCII value and comparing from there -- that's something that occurred to me too. Nice one, @KachiM.
Chris,
Furthermore, RANK works almost 3 times faster than the 1. informat - and, interestingly, even about 2 times faster than the PIB1. informat, even though the results of rank(b) and input(b,pib1.) are exactly the same. By the way, the advantage of both is that they aren't limited to ASCII, and on an EBCDIC machine return the position of the character in the corresponding collating sequence. The same is true (only in reverse - from a collating sequence position to its character) for the BYTE function and PIB1. format.
Paul D.
If you run the following on an ASCII machine:
data _null_ ; do r = 48 to 57 ; b = byte (r) ; put r= b= ; end ; run ;
you'll see in the log:
r=48 b=0 r=49 b=1 r=50 b=2 r=51 b=3 r=52 b=4 r=53 b=5 r=54 b=6 r=55 b=7 r=56 b=8 r=57 b=9
In other words, in the ASCII collating sequence, the character "0" is in position (i.e. rank) 48, and the rest of the digits follow ascending. Hence, subtracting 48 from the rank maps the byte sequence "0123456789" from its ranks 48-57 to the integers 0-9, which is what the doctor ordered.
However, one problem with hard coding -48 is, well, hard coding. This is because if datasp's code were executed on an EBCDIC machine (aka the mainframe), it would fail since in the EBCDIC collating sequence, the characters "0"-"9" occupy positions 240-249. Therefore, if datasp wanted the code to be portable (aka machine-independent), it would have to be coded rather in this vein:
data _null_ ; c = '000112010302' ; max = 0 ; r0 = rank ("0") ; do i = 1 to length(c) ; x = rank (char (c, i)) - r0 ; max = max <> x ; end ; put max= ; run ;
This way, it would execute with the expected result regardless of the encoding used on the machine where the code is run.
Paul D.
Everyone who contributed to the thread has been fantastic and I wish I had the ability to code or let alone think at that level.
How long have you(to each one of you who contributed) been using SAS to be so competent?
@MarkWik wrote:
Everyone who contributed to the thread has been fantastic and I wish I had the ability to code or let alone think at that level.
How long have you(to each one of you who contributed) been using SAS to be so competent?
Thanks, @MarkWik,
I've been using SAS for 20 years (started with version 6.12). FINDC and similarly adjustable functions were only introduced in SAS 9, though.
FreelanceReinhard,
While it's true that the FIND family was unveiled in version 9.0, the idea you offered here could be also implemented using INDEXC which had been available earlier - definitely since version 8 (though I suspect even since version 7).
Best
Paul D.
Oh yes, you're right: Tom's version of the solution could use INDEXC in lieu of FINDC:
h=10-indexc('9876543210 ',c);
INDEXC was already available in SAS 6.12.
@FreelanceReinh and @hashman Since indexc does the same thing, runs 36% faster than findc, and shorter function names don't count in this game, here is my revised entry:
dat have;
inpu k $12.;
card;
000112010302
0
1
2
3
4
5
6
7
8
9
0123456987
.
;
dat w;
se;
h=10-indexc('9876543210 ',k);
ru;
Art, CEO, AnalystFinder.com
Correct. I failed to rack my brain far enough back in time.
@MarkWikNot sure If i belong to the competent list, but have been user since Oct 2013, getting to 5 years+ 1 year prior to that of getting to know what is sas like a generic exposure. So yeah, a long way to go to catch up with 20,30 plusses in the list
wow such a great post, I have learned very much unique approaches from this post, THANK YOU all contributors
How about some "job security" solutions?
Hole-In-Three
proc format;
picture separate low-high='9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9';
%put MaxDigit: %sysfunc(max(%sysfunc(putn(%sysfunc(inputn(%sysfunc(compress("000112010302",'"')),16.)),separate.))));
Way-Over-Par (Recursion)
%macro maxdigit(digits,d);
%if &d= %then %let d=%length(&digits);
%if &d<=1 %then %substr(&digits,&d,1);
%else %sysfunc(max(%substr(&digits,&d,1),%maxdigit(&digits,%eval(&d-1))));
%mend;
%put MaxDigit: %maxdigit(000112010302);
proc optmodel;
str s = '000112010302';
put(max {k in 1..length(s)} char(s,k));
quit;
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
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.