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
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 秒
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
Hi! It works for a few elements. But I have several thousand. /Br Anders
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
Hi! VERY interesting solution. I can not use it, but quite good! /Br Anders
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 秒
Hi! This is a version of the classical "Bubble sort". Yes it works. /Br Anders
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
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
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
@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
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.
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
Hi! The hash solution works nicely in SAS ODA. /Br Anders
Join us for SAS Innovate 2025, our biggest and most exciting global event of the year, in Orlando, FL, from May 6-9. Sign up by March 14 for just $795.
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.
Ready to level-up your skills? Choose your own adventure.