File Exchange Pick of the Week

Our best user submissions

Sorting Structure Arrays based on Fields

Jiro's pick this week is Nested Struct Sort by Jake Hughey.

MATLAB has a nice function sortrows to sort matrices (numeric or cells) based on specific column(s). I use it often when I am doing some data management. If you have Statistics Toolbox, there are corresponding functions for dataset arrays and ordinal arrays.

Sometimes, I want to do a similar action on structure arrays. I want to be able to sort according to specific fields. In order to do that, it requires some data manipulations. Let's take a look at an example.

A = struct(...
    'name', {'mike', 'doug', 'steve', 'loren', 'jiro', 'brett', 'seth'}, ...
    'year', {2005, 2001, 1993, 1987, 2006, 2005, 1998}, ...
    'day', {'Mon', 'Fri', 'Wed', 'Fri', 'Mon', 'Mon', 'Mon'})

for id = 1:length(A)
    fprintf('%d\n',id)
    disp(A(id))
end
A = 
  1×7 struct array with fields:
    name
    year
    day
1
    name: 'mike'
    year: 2005
     day: 'Mon'
2
    name: 'doug'
    year: 2001
     day: 'Fri'
3
    name: 'steve'
    year: 1993
     day: 'Wed'
4
    name: 'loren'
    year: 1987
     day: 'Fri'
5
    name: 'jiro'
    year: 2006
     day: 'Mon'
6
    name: 'brett'
    year: 2005
     day: 'Mon'
7
    name: 'seth'
    year: 1998
     day: 'Mon'

Let's sort the array by the field "name". First you need to convert to a cell array:

Afields = fieldnames(A);
Acell = struct2cell(A);
sz = size(Acell)            % Notice that the this is a 3 dimensional array.
                            % For MxN structure array with P fields, the size
                            % of the converted cell array is PxMxN
sz =
     3     1     7

Once it's a cell array, you can sort using sortrows:

% Convert to a matrix
Acell = reshape(Acell, sz(1), []);      % Px(MxN)

% Make each field a column
Acell = Acell';                         % (MxN)xP

% Sort by first field "name"
Acell = sortrows(Acell, 1)
Acell =
  7×3 cell array
    {'brett'}    {[2005]}    {'Mon'}
    {'doug' }    {[2001]}    {'Fri'}
    {'jiro' }    {[2006]}    {'Mon'}
    {'loren'}    {[1987]}    {'Fri'}
    {'mike' }    {[2005]}    {'Mon'}
    {'seth' }    {[1998]}    {'Mon'}
    {'steve'}    {[1993]}    {'Wed'}

And convert it back to a structure array:

% Put back into original cell array format
Acell = reshape(Acell', sz);

% Convert to Struct
Asorted = cell2struct(Acell, Afields, 1);

for id = 1:length(Asorted)
    fprintf('%d\n',id)
    disp(Asorted(id))
end
1
    name: 'brett'
    year: 2005
     day: 'Mon'
2
    name: 'doug'
    year: 2001
     day: 'Fri'
3
    name: 'jiro'
    year: 2006
     day: 'Mon'
4
    name: 'loren'
    year: 1987
     day: 'Fri'
5
    name: 'mike'
    year: 2005
     day: 'Mon'
6
    name: 'seth'
    year: 1998
     day: 'Mon'
7
    name: 'steve'
    year: 1993
     day: 'Wed'

Simpler Approach

Do you want an easier way of doing it? Just use Jake's nestedSortStruct:

B = nestedSortStruct(A, 'name');

isequal(B, Asorted)
ans =
  logical
   1

You can even sort by multiple fields. For example, let's sort by "year" and then by "name":

C = nestedSortStruct(A, {'year', 'name'});

for id = 1:length(C)
    fprintf('%d\n',id)
    disp(C(id))
end
1
    name: 'loren'
    year: 1987
     day: 'Fri'
2
    name: 'steve'
    year: 1993
     day: 'Wed'
3
    name: 'seth'
    year: 1998
     day: 'Mon'
4
    name: 'doug'
    year: 2001
     day: 'Fri'
5
    name: 'brett'
    year: 2005
     day: 'Mon'
6
    name: 'mike'
    year: 2005
     day: 'Mon'
7
    name: 'jiro'
    year: 2006
     day: 'Mon'

Thanks for this entry, Jake. One recommendation I have is to include a couple of examples in the HELP text in the code.

Edit (R2017a)

From R2017a, you can use sortrows with tables to accomplish a similar task cleanly and efficiently.

Atable = struct2table(A);
Atable_sorted = sortrows(Atable,'name')
Atable_sorted =
  7×3 table
      name       year      day  
    _________    ____    _______
    {'brett'}    2005    {'Mon'}
    {'doug' }    2001    {'Fri'}
    {'jiro' }    2006    {'Mon'}
    {'loren'}    1987    {'Fri'}
    {'mike' }    2005    {'Mon'}
    {'seth' }    1998    {'Mon'}
    {'steve'}    1993    {'Wed'}

Comments

Give this a try and et us know what you think here or leave a comment for Jake.




Published with MATLAB® R2020b

|
  • print

Comments

To leave a comment, please click here to sign in to your MathWorks Account or create a new one.