SAS Tips from the Community

SAS tips from real SAS users like you
BookmarkSubscribeRSS Feed
🔒 This topic is locked. We are no longer accepting replies to this topic. Need further help? Please sign in and ask a new question.
mkeintz
PROC Star

The article SAS Tip: Sorting an Array in Descending Order - SAS Support Communities shows how to use call sortn (or call sortc) to sort an array in descending order, even though the call routines only support ascending order.  The "trick" is to list variables in an array in reverse sequence.  The example simply says to use, instead of "array x{*} v1-v5;":

 array rev[*] v5-v1;
call sortn(of rev[*]);

to generate descending order for variables V1 through V5.

 

But what if you don't have such conveniently named variables?  Let's say you have variables A, B, C, .... ,Z. and you want vars G through S to have values in descending order.  There is no way to declare the needed array without naming each array element in reverse order prior to the call sortn.  You can't simply use the endpoint names in the array declaration to support a descending sort.

 

But you can use the endpoint names to define the array and a corresponding ordered hash object, and then retrieve the descending values back into the variables from endpoint to endpoint.  You do declare an array, but you don't need to list (or even know the names) of the interior variables:

 

data have;
  input 
a b c d e f g h i j  k  l  m  n  o  p  q  r  s  t  u  v  w  x  y  z;
datalines;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
run;

data want (drop=_: ii);
  set have;
  array vals  {*} G -- S;

  put "Before: " (g--s) (=);
  if _n_=1 then do;
    _value=.;
    declare hash hh (ordered:'d',multidata:'Y');
      hh.definekey('_value');
      hh.definedata('_value');
      hh.definedone();
    declare hiter hi ('hh');
  end;

  do ii=1 to dim(vals);
    hh.add(key:vals{ii},data:vals{ii});  *See note*;
  end;

  do _rc=hi.last() by 0 until (hi.prev()^=0);
    ii=ii-1;
    vals{ii}=_value;
  end;
  hh.clear();
  put 'After:  ' (g--s) (=);
run;

Admittedly more overhead than an array statement plus a call sortn statement, but you avoid the requirement of correctly sequencing the names of all the variables in the array.  The longer the array, the more benefit from this technique.

 

Note:

For a couple of days, I had erroneously used the hh.replace() method, but it prevents proper tracking of duplicate key values (which is why I used the multidata:"Y" option).  That has now been changed to hh.add(), which honors the duplicates.

 

Thank you @FreelanceReinh

--------------------------
The hash OUTPUT method will overwrite a SAS data set, but not append. That can be costly. Consider voting for Add a HASH object method which would append a hash object to an existing SAS data set

Would enabling PROC SORT to simultaneously output multiple datasets be useful? Then vote for
Allow PROC SORT to output multiple datasets

--------------------------

sas-innovate-white.png

Our biggest data and AI event of the year.

Don’t miss the livestream kicking off May 7. It’s free. It’s easy. And it’s the best seat in the house.

Join us virtually with our complimentary SAS Innovate Digital Pass. Watch live or on-demand in multiple languages, with translations available to help you get the most out of every session.

 

Register now!

Visit a random SAS tip This SAS Tips board is not open for replies or comments, but we welcome your feedback and questions. Have a question or comment about this tip? Start a new topic in one of our discussion boards, and reference this tip topic.
Discussion stats
  • 0 replies
  • 785 views
  • 4 likes
  • 1 in conversation