Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Sort A Structure On Multiple Fields

740 views
Skip to first unread message

John Roberts

unread,
Mar 3, 2010, 5:40:23 PM3/3/10
to
I've been searching for a while, but haven't been able to find an easy way to sort a structure based on multiple fields (kind of like sortrows, but for a structure).

For example, I have a structure:

data = struct('CL', [0.51 0.51 0.52 0.52 0.55 0.55], 'Mach', [0.7 0.8 0.7 0.8 0.7 0.8], 'CG', [.25 .27 .25 .30 .27 .25])

If I wanted to sort first by CG, then Mach, and finally by CL, the result would be:

CG = [.25 .25 .25 .27 .27 .30]
Mach = [0.7 0.7 0.8 0.7 0.8 0.8]
CL = [ .51 .52 .55 .55 .51 .52]

Any ideas? Thank you for your help!

John

Alan B

unread,
Mar 3, 2010, 7:12:04 PM3/3/10
to
"John Roberts" <johnj...@hotmail.com> wrote in message <hmmogn$s07$1...@fred.mathworks.com>...

To me, "sort a structure" implies sorting the elements of a structure array. What you're asking to do is exactly accomplished by sortrows.

d=[data.CL' data.Mach' data.CG'];
d=sortrows(d,[3 2 1])
data.CG=d(:,3)'; data.Mach=d(:,2)'; data.CL=d(:,1)';

Am I misunderstanding?

John Roberts

unread,
Mar 3, 2010, 7:35:19 PM3/3/10
to
Thanks for the quick response. That's pretty much what I had in mind, except I am looking for a more general case where one of the fields in the 'data' struct could be a cell of strings. I would then want to be able to sort by the string as well.

For example, if I add data.Names, I would want to sort by CG, then by Names, then by CL.

John Roberts

unread,
Mar 3, 2010, 8:19:22 PM3/3/10
to
Orderfields seems to do alright, but it can only sort one column at a time.

Alan B

unread,
Mar 4, 2010, 1:20:22 AM3/4/10
to
"John Roberts" <johnj...@hotmail.com> wrote in message <hmn1qq$ifg$1...@fred.mathworks.com>...

> Orderfields seems to do alright, but it can only sort one column at a time.

I see. Doesn't this mean you'll have to manually write comparison functions for every field? The most straightforward solution I can think of is:
-compute some sort of ordered index for each non-scalar field, as well as a "lookup table", probably as a cell array
-populate a 2D array with the values of the scalar fields OR the ordered indices
-call sortrows
-convert back to your original struct format by using the ordered indices to reference the lookup table

I'm not sure if Matlab has anything more direct than this, hopefully someone else has a better suggestion.

us

unread,
Mar 4, 2010, 5:29:21 AM3/4/10
to
"John Roberts" <johnj...@hotmail.com> wrote in message <hmmv87$6up$1...@fred.mathworks.com>...

> Thanks for the quick response. That's pretty much what I had in mind, except I am looking for a more general case where one of the fields in the 'data' struct could be a cell of strings. I would then want to be able to sort by the string as well.
>
> For example, if I add data.Names, I would want to sort by CG, then by Names, then by CL.

one of the (not so many) solutions

% the data
d.a=1:4;
d.b=[-1,-5,-10,-2];
d.c=[4,1,5,3];
d.s={'b','c','a','a'};
% - sort according to field #
csort=[4,3];
% the engine
fn=fieldnames(d);
c=struct2cell(d);
[ia,ix,ix]=cellfun(@unique,c,'uni',false);
cx=cat(1,ix{:}).';
[cs,cxx]=sortrows(cx,csort);
cn=num2cell(cs.',2);
ns=cellfun(@(x,y) x(y),ia,cn,'uni',false);
r=cell2struct(ns,fn);
% the result
disp(d);
disp(r);
%{
% d =
a: [1 2 3 4]
b: [-1 -5 -10 -2]
c: [4 1 5 3]
s: {'b' 'c' 'a' 'a'}
% r =
a: [4 3 1 2]
b: [-2 -10 -1 -5]
c: [3 5 4 1]
s: {'a' 'a' 'b' 'c'}
%}

us

John Roberts

unread,
Mar 4, 2010, 12:18:21 PM3/4/10
to
Thanks us, that does the trick.

I see that you converted the struct2cell. Are there any other advantages to using structs other than using fieldnames?

How come there aren't struct functions to do this? MS Excel has a very nice sort routine, I would have thought this would be easy to implement in Matlab? Or is it a philosophical issue? Should I not be using Matlab to sort arrays of data? What if I want to do Excel-type things in Matlab?

Steven Lord

unread,
Mar 4, 2010, 1:36:50 PM3/4/10
to

"John Roberts" <johnj...@hotmail.com> wrote in message
news:hmoq0t$9ve$1...@fred.mathworks.com...

The problem you described involved sorting the fields of a scalar struct
based on the contents of other fields of that struct. In your case, where
all the fields were the same size and data type, that makes sense. But in
the more general case:

S = struct('CG', (1:10).', 'mach', single(magic(6)), 'CL', 'Live long and
prosper')

what would it mean to sort S "first by CG, then Mach, and finally by CL"?
CG is a 10-by-1 array of doubles, mach is a 6-by-6 array of singles, and CL
is a 1-by-21 array of chars, so no two of the fields contain data of the
same data type or size. [Yes, the example is a bit contrived, but I'm sure
you can think of scenarios where a struct array may contain fields of
different types or sizes.]

If all your data is homogeneous in type and size, you might want to store it
in a regular array rather than a struct array. From your original example:

CL = [0.51 0.51 0.52 0.52 0.55 0.55];
Mach = [0.7 0.8 0.7 0.8 0.7 0.8];
CG = [.25 .27 .25 .30 .27 .25];
data = [CL; Mach; CG];

and then a sort of data just involves SORTROWS directly.

--
Steve Lord
sl...@mathworks.com
comp.soft-sys.matlab (CSSM) FAQ: http://matlabwiki.mathworks.com/MATLAB_FAQ


Oleg Komarov

unread,
Mar 4, 2010, 3:16:27 PM3/4/10
to
In addition to Steven's considerations you can create your own structure class with a sortfields method...Surely this kind of structure would be more rigid than the more general one (it is already implemented in a sort of fashion by the dataset object from the Statistics toolbox)

oleg

0 new messages