BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
AndersS
Pyrite | Level 9

Hi! In the Data-step we can use  CALL SORTN( of   ARRN(*));  to sort all elements in the array ARRN in increasing order. It works fine for both ordinary arrays and _temporary_ arrays.

If the array is not _temporary_ then we can specify the variable names,  like CALL SORTN( of ARRN3-ARRN10); to sort only elements 3 to 10. (Note that it is not possible to specify the array element names.  CALL SORTN( of ARRN(3) -ARRN(10));   gives ERROR!)

 

My question: Is it possible to sort only PART of the _temporary_ array  in some way. This can be useful.
I have tried a number of different ways, but it did not work.

 

_Temporary_ arrays are VERY much faster than ordinary arrays. (A way of speeding up ordinary arrays is NOT to include them in the output data set. i.e. they are not included in the file buffer).
Many thanks in advance!   /Br Anders

Anders Sköllermo (Skollermo in English)
1 ACCEPTED SOLUTION

Accepted Solutions
Ksharp
Super User

Just code it on your own ,if you have too many members in _temporary_ array.

 

data _null_;
array a[10] _temporary_ (1 1 4 3 2   5 4 3 2 1);
/*sort the member of arrary from 6th to 10th*/
do i=6 to 10;
 do j=i+1 to 10;
  if a{i}>a{j} then do;temp=a{i};a{i}=a{j};a{j}=temp; end;
 end;
end;
drop i j temp;

/*print this array*/
do i=1 to 10;
 put a{i}= ;
end;
run;

 

344  data _null_;
345  array a[10] _temporary_ (1 1 4 3 2   5 4 3 2 1);
346  /*sort the member of arrary from 6th to 10th*/
347  do i=6 to 10;
348   do j=i+1 to 10;
349    if a{i}>a{j} then do;temp=a{i};a{i}=a{j};a{j}=temp; end;
350   end;
351  end;
352  drop i j temp;
353
354  /*print this array*/
355  do i=1 to 10;
356   put a{i}= ;
357  end;
358  run;

a[1]=1
a[2]=1
a[3]=4
a[4]=3
a[5]=2
a[6]=1
a[7]=2
a[8]=3
a[9]=4
a[10]=5
NOTE: “DATA 语句”所用时间(总处理时间):
      实际时间          0.03 秒
      CPU 时间          0.00 秒




View solution in original post

26 REPLIES 26
data_null__
Jade | Level 19

You cannot use a SAS-Variable-List to reference elements of a temporary array, because they are not variables.

 

But you can sort elements of a temporary array if you reference them properly.  array-name[subscript].  I don't know if my example is adequate but seems reasonable.

 

48         data _null_;
49            array a[5] _temporary_ (1 1 4 3 2);
50            do i = 1 to dim(a); put (a[i])(=); end;
51            put ' ';
52            call sortn(a[3],a[4],a[5]);
53            do i = 1 to dim(a); put (a[i])(=); end;
54            run;

a[1]=1
a[2]=1
a[3]=4
a[4]=3
a[5]=2

a[1]=1
a[2]=1
a[3]=2
a[4]=3
a[5]=4

 

AndersS
Pyrite | Level 9

Hi! It works for a few elements. But I have several thousand. /Br Anders

Anders Sköllermo (Skollermo in English)
FreelanceReinh
Jade | Level 19

Hi @AndersS,

 


@AndersS wrote:

Hi! It works for a few elements. But I have several thousand. /Br Anders


This should not be an obstacle. You can build the list for the argument of CALL SORTN programmatically.

 

Example:

/* Create two lists of array elements */

data _null_;
length g1 g2 $80;
do i=37 to 45;
  g1=catx(',',g1,cat('a[',i,']'));
end;
call symputx('group1',g1);
do i=5 to 77 by 9;
  g2=catx(',',g2,cat('a[',i,']'));
end;
call symputx('group2',g2);
run;

/* Sort those parts of a temporary array */

data _null_;
array a[81] _temporary_;
do i=1 to dim(a);
  a[i]=82-i;
end;
call sortn(&group1);
call sortn(&group2);
do i=1 to dim(a);
  put a[i] 3. @;
  if ~mod(i,9) then put;
end;
run;

Result:

 81 80 79 78  5 76 75 74 73
 72 71 70 69 14 67 66 65 64
 63 62 61 60 23 58 57 56 55
 54 53 52 51 32 49 48 47 46
 37 38 39 40 41 42 43 44 45
 36 35 34 33 50 31 30 29 28
 27 26 25 24 59 22 21 20 19
 18 17 16 15 68 13 12 11 10
  9  8  7  6 77  4  3  2  1
AndersS
Pyrite | Level 9

Hi! VERY interesting solution. I can not use it, but quite good!  /Br Anders

Anders Sköllermo (Skollermo in English)
Ksharp
Super User

Just code it on your own ,if you have too many members in _temporary_ array.

 

data _null_;
array a[10] _temporary_ (1 1 4 3 2   5 4 3 2 1);
/*sort the member of arrary from 6th to 10th*/
do i=6 to 10;
 do j=i+1 to 10;
  if a{i}>a{j} then do;temp=a{i};a{i}=a{j};a{j}=temp; end;
 end;
end;
drop i j temp;

/*print this array*/
do i=1 to 10;
 put a{i}= ;
end;
run;

 

344  data _null_;
345  array a[10] _temporary_ (1 1 4 3 2   5 4 3 2 1);
346  /*sort the member of arrary from 6th to 10th*/
347  do i=6 to 10;
348   do j=i+1 to 10;
349    if a{i}>a{j} then do;temp=a{i};a{i}=a{j};a{j}=temp; end;
350   end;
351  end;
352  drop i j temp;
353
354  /*print this array*/
355  do i=1 to 10;
356   put a{i}= ;
357  end;
358  run;

a[1]=1
a[2]=1
a[3]=4
a[4]=3
a[5]=2
a[6]=1
a[7]=2
a[8]=3
a[9]=4
a[10]=5
NOTE: “DATA 语句”所用时间(总处理时间):
      实际时间          0.03 秒
      CPU 时间          0.00 秒




AndersS
Pyrite | Level 9

Hi! This is a version of the classical "Bubble sort". Yes it works. /Br Anders

Anders Sköllermo (Skollermo in English)
yabwon
Onyx | Level 15

You already have a solution for your question, but just for fun one more:

/* just to print arrays elements */
/* EDIT: */
/* just to print arrays elements */
%macro prArr(A,s=LBound(&A.),e=HBound(&A.),b=1,i=i);
put; do &i. = &s. to &e. by &b.; put &A.[i]=; end;
%mend prArr;

/* list part of array you want to sort */
%macro ArrElem(A,s,e,b=1);
%local i;
%do i = &s. %to &e. %by &b.; %if (&i. NE &s.) %then,; &A.[&i.] %end;
%mend ArrElem;



data _null_;
  array a[10] _temporary_ (5 4 3 2 1  5 4 3 2 1);

  %prArr(a)

  /* one part... */
  call sortn(%ArrElem(a,6,10));

  %prArr(a)
  
  /* [EDIT:] */
  /* or even two parts */
  call sortn(%ArrElem(a,1,3),%ArrElem(a,8,10));

  %prArr(a)
run;

 

Bart

_______________
Polish SAS Users Group: www.polsug.com and communities.sas.com/polsug

"SAS Packages: the way to share" at SGF2020 Proceedings (the latest version), GitHub Repository, and YouTube Video.
Hands-on-Workshop: "Share your code with SAS Packages"
"My First SAS Package: A How-To" at SGF2021 Proceedings

SAS Ballot Ideas: one: SPF in SAS, two, and three
SAS Documentation



yabwon
Onyx | Level 15

One more, just for fun, extension, a bit of "syntactic sugar"

 

%macro ArrElem(A,elements);
%local i n k o s e b;
%let n=%sysfunc(countw(&elements., %str( )));
%do k=1 %to &n.;
  %let o = %scan(&elements.,&k.,%str( ));
  %let s = %scan(&o.,1,:);
  %let e = %scan(&o.,2,:);
  %let b = %scan(&o.,3,:);
  %if &e.= %then %let e=&s.;
  %if &b.= %then %let b=1;
  %if (&k. NE 1) %then,;
  %do i = &s. %to &e. %by &b.; %if (&i. NE &s.) %then,; &A.[&i.] %end;
%end;
%mend ArrElem;

options mprint;
data _null_;
  array a[10] _temporary_ (5 4 3 2 1  5 4 3 2 1);

  %prArr(a)

  /* one part... */
  call sortn( %ArrElem(a,6:10) );

  %prArr(a)

  /* or even two parts */
  call sortn( %ArrElem(a,1:5:2 8:10) );

  %prArr(a)
run;


data _null_;
  array a[10] _temporary_ (50 5 40 4 30 3 20 2 10 1);

  %prArr(a)

  /* sort even and odd */
  call sortn( %ArrElem(a,1:9:2 2:10:2) );

  %prArr(a)
run;

 

Bart

_______________
Polish SAS Users Group: www.polsug.com and communities.sas.com/polsug

"SAS Packages: the way to share" at SGF2020 Proceedings (the latest version), GitHub Repository, and YouTube Video.
Hands-on-Workshop: "Share your code with SAS Packages"
"My First SAS Package: A How-To" at SGF2021 Proceedings

SAS Ballot Ideas: one: SPF in SAS, two, and three
SAS Documentation



AndersS
Pyrite | Level 9

Hi! VERY interesting solution by Bart.  Yes it works. I have just tested it.

 

I  dont have any use if ths solution just now.

But I think that these discussions are REALLY GREAT!

/Br Anders

Anders Sköllermo (Skollermo in English)
PeterClemmensen
Tourmaline | Level 20

@AndersS , I see you found your answer. 

 

However, I will chime in and refer you to the article QuickSorting An Array by Paul Dorfman (aka the @hashman).

 

The %Qsort macro takes an array and sorts it using the Quicksort algorithm. Also, the macro takes the optional parameters lb and hb, so you can easily sort elements 3 to 10.

 

I recommend reading the entire article. Pure gold 🙂

 

Br

AndersS
Pyrite | Level 9
Hi! Many thanks!

BUT, %QSORT does NOT work in SAS ODA.

Solution: Find the code for %QSORT and include it.

Perhaps later on I will do that.

CALL SORTN is rather good. Good enough now for my needs.
/Br Anders

Anders Sköllermo fil.dr., Sandgränd 13, 178 40 Ekerö, 073-5077373,
anders.skollermo@one.se
Anders Sköllermo (Skollermo in English)
hashman
Ammonite | Level 13

Hi, Anders:

You can copy the entire QSORT macro directly from the pdf paper Peter Clemmensen has linked, then use it as described in the (pretty extensive) comments in the header. Another advantages of using qsort or another method not based on SORTN/C is that you can also sort descending and control what to do with duplicates. 

If you don't like to use QSORT for any reason, you can use the hash object to do what you need:

 

data _null_ ;                                                                                                                                                                                                                                                   
  retain lb 3 hb 8 order "a" ; * use d for descending ;                                                                                                                                                                                                       
  array arr [10] (2 10 444 333 111 888 777 666 4 5) ;                                                                                                                                                                                                          
  if _n_ = 1 then do ;                                                                                                                                                                                                                                          
    dcl hash h (ordered:order, multidata:"y") ;                                                                                                                                                                                                                 
    h.definekey ("k") ;                                                                                                                                                                                                                                         
    h.definedone () ;                                                                                                                                                                                                                                           
    dcl hiter hi ("h") ;                                                                                                                                                                                                                                        
  end ;                                                                                                                                                                                                                                                         
  do _n_ = lb to hb ;                                                                                                                                                                                                                                           
    k = arr[_n_] ;                                                                                                                                                                                                                                              
    h.add() ;                                                                                                                                                                                                                                                   
  end ;                                                                                                                                                                                                                                                         
  do _n_ = lb by 1 while (hi.next() = 0) ;                                                                                                                                                                                                                      
    arr[_n_] = k ;                                                                                                                                                                                                                                              
  end ;                                                                                                                                                                                                                                                        
  put arr(*) ;                                                                                                                                                                                                                                                  
run ;      

Alternatively, you can use CALL SORTN against an auxiliary array with the required range and then copy the sorted items back into the array in question, for example:

 

 

%let range = 3:8 ; 
data _null_ ;
array arr [10] (2 10 444 333 111 888 777 666 4 5) ;
array aux [&range] _temporary_ ;
do _n_ = lbound (aux) to hbound (aux) ;
aux [_n_] = arr [_n_] ;
end ;
call sortn (of aux[*]) ;
do _n_ = lbound (aux) to hbound (aux) ;
arr [_n_] = aux [_n_] ;
end ;
put arr(*) ;
run ;

As far as KSharp's bubble sort is concerned, it's okay for a few items but will get painfully slow even for a thousand since its running time is O(N**2), while all of the above approaches can handle millions of array items in a second or so. 

 

Kind regards

Paul D.

 

AndersS
Pyrite | Level 9

Hi Paul!  GREAT. I will use the code from the paper.

The SAS Community and all these discussions are VERY useful. I have used SAS since 1981. I am  writing another paper about quantiles, and try NOT to use very SAS specific solutions. /BR Anders

 

Anders Sköllermo (Skollermo in English)
AndersS
Pyrite | Level 9

Hi! The hash solution works nicely in SAS ODA. /Br Anders

Anders Sköllermo (Skollermo in English)

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

Register now!

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 26 replies
  • 1271 views
  • 28 likes
  • 8 in conversation