PROC Star
Posts: 8,164

# How to use call sortn with a multidimensional array

In response to a post earlier today I used a slightly modified version of one of Paul Dorfman's old sort macros to do what I wanted, but I was wondering if one could accomplish the same result using call sortn.  Yes, I know that the problem can be addressed with either a hash or proc surveyselect, but I'm more interested in knowing how to sort a multidimensional array based on just one of the dimensions.

In the present case I was trying to randomly assign values to 5 different groups over 10,000 iterations. e.g., I think the following does what I want to know if/how it could be done using call sortn using just one two-dimensional array:

%let n=1000;
%macro combsort (arr1 =, arr2=, order= <);
drop __:;
do __g = hbound (&arr1) - 1 by 0 while (__s or __g > 1);
__g = int (__g / 1.3);
if __g in (0 ) then __g = 1;
else if __g in (9, 10) then __g = 11;
__s = 0;
do __j = lbound (&arr1) to hbound (&arr1) - __g;
__k = __j + __g;
if &arr1[__j] &order &arr1[__k] then continue;
__t = &arr1[__j];
&arr1[__j] = &arr1[__k];
&arr1[__k] = __t;
__t = &arr2[__j];
&arr2[__j] = &arr2[__k];
&arr2[__k] = __t;
__s = 1;
end;
end;
%mend;
data want (keep=trial group;
array values(&n.);
do until (eof);
set hej end=eof;
i+1;
values(i)=y;
end;
array ordering(&n.);
array group1_(%eval(&n./5));
array group2_(%eval(&n./5));
array group3_(%eval(&n./5));
array group4_(%eval(&n./5));
array group5_(%eval(&n./5));
do trial=1 to 10000;
do i=1 to &n.;
ordering(i)=ranuni(0);
end;
%combsort(arr1=ordering, arr2=values);
k=0;
do i=1 to 5;
do j=1 to %eval(&n./5);
k+1;
if i eq 1 then group1_(j)=values(k);
else if i eq 2 then group2_(j)=values(k);
else if i eq 3 then group3_(j)=values(k);
else if i eq 4 then group4_(j)=values(k);
else if i eq 5 then group5_(j)=values(k);
end;
end;
output;
end;
run;

Super User
Posts: 10,778

## Re: How to use call sortn with a multidimensional array

Art.T

That is easy. Using macro variable to wrap these array elements.

If you know some algorithm about sorting, then you don't need function SORTN() either .

```data _null_;
length x \$ 200;
do i=1 to 2;
do j=1 to 3;
x=catx(',',x,cats('a{',i,',',j,'}'));
end;
call symputx(cats('a',i),x);
call missing(x);
end;
run;
%put _user_;

data _null_;
array a{2,3} _temporary_ (2 4 1
5 3 2 ) ;

call sortn(&a1);
call sortn(&a2);

do i=1 to 2;
do j=1 to 3;
put a{i,j}= @;
end;
put / ;
end;
run;

```

Ksharp

PROC Star
Posts: 8,164

## Re: How to use call sortn with a multidimensional array

: Thanks for trying, but not quite what I was looking for.  My example apparently wasn't sufficiently clear.  Hopefully, the following example conveys the intent better:

Have:
19 97 40 26
92 96 54 53
05 07 82 52

Want Possiblity 1 (sorted by the bottom row's values):
19 97 26 40
92 96 53 54
05 07 52 82

Want Possiblity 2 (sorted by the right most column's values):
19 97 40 26
05 07 82 52
92 96 54 53

I know how to accomplish it with some macro code sorting related one-dimensional arrays, but was hoping sortn and sortc could handle it.  Thus far, the calls don't appear to have that functionality.

Super User
Posts: 8,108

## Re: How to use call sortn with a multidimensional array

Why not write it to a dataset and then use proc sort?  Would easily handle the second example.  To do the first just write it out by column instead of rows.

Super User
Posts: 10,778

## Re: How to use call sortn with a multidimensional array

Arthur.T ,

Oh. I do not think call sortn() can do this. call sortn() is only used to process an simple observation(e.g a record) , not manipulate a whole vector .For your purpose, the RETAIN statement is more suited.

Possibility 1:

```data _null_;
array a{3,4} _temporary_ (19 97 40 26
92 96 54 53
05 07 82 52 ) ;
if a{1,3} gt a{1,4} then do;
temp=a{1,4};
a{1,4}=a{1,3};
a{1,3}=temp;

temp=a{2,4};
a{2,4}=a{2,3};
a{2,3}=temp;

temp=a{3,4};
a{3,4}=a{3,3};
a{3,3}=temp;
end;

do i=1 to 3;
do j=1 to 4;
put a{i,j} 3. @;
end;
put / ;
end;
run;
```

Possibility 2:

```data _null_;
array a{3,4} _temporary_ (19 97 40 26
92 96 54 53
05 07 82 52 ) ;
do i=1 to 3;
do j=i+1 to 3;
if a{i,4} gt a{j,4} then do;
temp=a{j,4};
a{j,4}=a{i,4};
a{i,4}=temp;

temp=a{j,3};
a{j,3}=a{i,3};
a{i,3}=temp;

temp=a{j,2};
a{j,2}=a{i,2};
a{i,2}=temp;

temp=a{j,1};
a{j,1}=a{i,1};
a{i,1}=temp;
end;
end;
end;

do i=1 to 3;
do j=1 to 4;
put a{i,j} 3. @;
end;
put / ;
end;
run;

```

Ksharp

Posts: 3,167

## Re: How to use call sortn with a multidimensional array

Ksharp, not to pick on you. Although temporary array is automatically retained, but there is no 'retain statement' in either of your code like you suggested.

Haikuo

Super User
Posts: 10,778

## Re: How to use call sortn with a multidimensional array

Yeah. What I mean is what TOM mean, using a dataset hold these data and use RETAIN statement to reorder these variables . I think it would be easier and better for this case.

PROC Star
Posts: 8,164

## Re: How to use call sortn with a multidimensional array

Thanks to Tom and Ksharp.  I've marked this thread as 'assumed answered' as it appears that the answer is simply that call sortn and call sortc can't be used this way.  I'm going to stick with Paul Dorfman's macro for separating multidimensional arrays into a set of one dimensional arrays, sort the desired dimension, and shift the other arrays during the sorting process.

That approach was the most suitable in the present case as the array had to be created and sorted, on the fly, separately for each record.  Using retain, or re-writing the file and sorting it, added too many unnecessary complications.

Discussion stats
• 7 replies
• 789 views
• 6 likes
• 4 in conversation