bio_img_pick

Pick of the Week

Recognizing outstanding contributions from the MATLAB ecosystem

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

댓글

댓글을 남기려면 링크 를 클릭하여 MathWorks 계정에 로그인하거나 계정을 새로 만드십시오.