{"id":2595,"date":"2010-09-17T13:50:22","date_gmt":"2010-09-17T13:50:22","guid":{"rendered":"https:\/\/blogs.mathworks.com\/pick\/2010\/09\/17\/sorting-structure-arrays-based-on-fields\/"},"modified":"2020-10-05T03:39:24","modified_gmt":"2020-10-05T07:39:24","slug":"sorting-structure-arrays-based-on-fields","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/pick\/2010\/09\/17\/sorting-structure-arrays-based-on-fields\/","title":{"rendered":"Sorting Structure Arrays based on Fields"},"content":{"rendered":"\r\n\r\n<div class=\"content\"><p><a href=\"http:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/authors\/15007\">Jiro<\/a>'s pick this week is <a href=\"http:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/28573-nested-sort-of-structure-arrays\">Nested Struct Sort<\/a> by <a href=\"http:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/authors\/106570\">Jake Hughey<\/a>.<\/p><p>MATLAB has a nice function <a href=\"http:\/\/www.mathworks.com\/access\/helpdesk\/help\/techdoc\/ref\/sortrows.html\"><tt>sortrows<\/tt><\/a> 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 <a href=\"http:\/\/www.mathworks.com\/products\/statistics\/\">Statistics Toolbox<\/a>, there are corresponding functions for <a href=\"http:\/\/www.mathworks.com\/access\/helpdesk\/help\/toolbox\/stats\/dataset.sortrows.html\">dataset arrays<\/a> and <a href=\"\">ordinal arrays<\/a>.<\/p><p>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.<\/p><pre class=\"codeinput\">A = struct(<span class=\"keyword\">...<\/span>\r\n    <span class=\"string\">'name'<\/span>, {<span class=\"string\">'mike'<\/span>, <span class=\"string\">'doug'<\/span>, <span class=\"string\">'steve'<\/span>, <span class=\"string\">'loren'<\/span>, <span class=\"string\">'jiro'<\/span>, <span class=\"string\">'brett'<\/span>, <span class=\"string\">'seth'<\/span>}, <span class=\"keyword\">...<\/span>\r\n    <span class=\"string\">'year'<\/span>, {2005, 2001, 1993, 1987, 2006, 2005, 1998}, <span class=\"keyword\">...<\/span>\r\n    <span class=\"string\">'day'<\/span>, {<span class=\"string\">'Mon'<\/span>, <span class=\"string\">'Fri'<\/span>, <span class=\"string\">'Wed'<\/span>, <span class=\"string\">'Fri'<\/span>, <span class=\"string\">'Mon'<\/span>, <span class=\"string\">'Mon'<\/span>, <span class=\"string\">'Mon'<\/span>})\r\n\r\n<span class=\"keyword\">for<\/span> id = 1:length(A)\r\n    fprintf(<span class=\"string\">'%d\\n'<\/span>,id)\r\n    disp(A(id))\r\n<span class=\"keyword\">end<\/span>\r\n<\/pre><pre class=\"codeoutput\">A = \r\n  1&times;7 struct array with fields:\r\n    name\r\n    year\r\n    day\r\n1\r\n    name: 'mike'\r\n    year: 2005\r\n     day: 'Mon'\r\n2\r\n    name: 'doug'\r\n    year: 2001\r\n     day: 'Fri'\r\n3\r\n    name: 'steve'\r\n    year: 1993\r\n     day: 'Wed'\r\n4\r\n    name: 'loren'\r\n    year: 1987\r\n     day: 'Fri'\r\n5\r\n    name: 'jiro'\r\n    year: 2006\r\n     day: 'Mon'\r\n6\r\n    name: 'brett'\r\n    year: 2005\r\n     day: 'Mon'\r\n7\r\n    name: 'seth'\r\n    year: 1998\r\n     day: 'Mon'\r\n<\/pre><p>Let's sort the array by the field \"name\". First you need to convert to a cell array:<\/p><pre class=\"codeinput\">Afields = fieldnames(A);\r\nAcell = struct2cell(A);\r\nsz = size(Acell)            <span class=\"comment\">% Notice that the this is a 3 dimensional array.<\/span>\r\n                            <span class=\"comment\">% For MxN structure array with P fields, the size<\/span>\r\n                            <span class=\"comment\">% of the converted cell array is PxMxN<\/span>\r\n<\/pre><pre class=\"codeoutput\">sz =\r\n     3     1     7\r\n<\/pre><p>Once it's a cell array, you can sort using <tt>sortrows<\/tt>:<\/p><pre class=\"codeinput\"><span class=\"comment\">% Convert to a matrix<\/span>\r\nAcell = reshape(Acell, sz(1), []);      <span class=\"comment\">% Px(MxN)<\/span>\r\n\r\n<span class=\"comment\">% Make each field a column<\/span>\r\nAcell = Acell';                         <span class=\"comment\">% (MxN)xP<\/span>\r\n\r\n<span class=\"comment\">% Sort by first field \"name\"<\/span>\r\nAcell = sortrows(Acell, 1)\r\n<\/pre><pre class=\"codeoutput\">Acell =\r\n  7&times;3 cell array\r\n    {'brett'}    {[2005]}    {'Mon'}\r\n    {'doug' }    {[2001]}    {'Fri'}\r\n    {'jiro' }    {[2006]}    {'Mon'}\r\n    {'loren'}    {[1987]}    {'Fri'}\r\n    {'mike' }    {[2005]}    {'Mon'}\r\n    {'seth' }    {[1998]}    {'Mon'}\r\n    {'steve'}    {[1993]}    {'Wed'}\r\n<\/pre><p>And convert it back to a structure array:<\/p><pre class=\"codeinput\"><span class=\"comment\">% Put back into original cell array format<\/span>\r\nAcell = reshape(Acell', sz);\r\n\r\n<span class=\"comment\">% Convert to Struct<\/span>\r\nAsorted = cell2struct(Acell, Afields, 1);\r\n\r\n<span class=\"keyword\">for<\/span> id = 1:length(Asorted)\r\n    fprintf(<span class=\"string\">'%d\\n'<\/span>,id)\r\n    disp(Asorted(id))\r\n<span class=\"keyword\">end<\/span>\r\n<\/pre><pre class=\"codeoutput\">1\r\n    name: 'brett'\r\n    year: 2005\r\n     day: 'Mon'\r\n2\r\n    name: 'doug'\r\n    year: 2001\r\n     day: 'Fri'\r\n3\r\n    name: 'jiro'\r\n    year: 2006\r\n     day: 'Mon'\r\n4\r\n    name: 'loren'\r\n    year: 1987\r\n     day: 'Fri'\r\n5\r\n    name: 'mike'\r\n    year: 2005\r\n     day: 'Mon'\r\n6\r\n    name: 'seth'\r\n    year: 1998\r\n     day: 'Mon'\r\n7\r\n    name: 'steve'\r\n    year: 1993\r\n     day: 'Wed'\r\n<\/pre><p><b>Simpler Approach<\/b><\/p><p>Do you want an easier way of doing it? Just use Jake's <tt>nestedSortStruct<\/tt>:<\/p><pre class=\"codeinput\">B = nestedSortStruct(A, <span class=\"string\">'name'<\/span>);\r\n\r\nisequal(B, Asorted)\r\n<\/pre><pre class=\"codeoutput\">ans =\r\n  logical\r\n   1\r\n<\/pre><p>You can even sort by multiple fields. For example, let's sort by \"year\" and then by \"name\":<\/p><pre class=\"codeinput\">C = nestedSortStruct(A, {<span class=\"string\">'year'<\/span>, <span class=\"string\">'name'<\/span>});\r\n\r\n<span class=\"keyword\">for<\/span> id = 1:length(C)\r\n    fprintf(<span class=\"string\">'%d\\n'<\/span>,id)\r\n    disp(C(id))\r\n<span class=\"keyword\">end<\/span>\r\n<\/pre><pre class=\"codeoutput\">1\r\n    name: 'loren'\r\n    year: 1987\r\n     day: 'Fri'\r\n2\r\n    name: 'steve'\r\n    year: 1993\r\n     day: 'Wed'\r\n3\r\n    name: 'seth'\r\n    year: 1998\r\n     day: 'Mon'\r\n4\r\n    name: 'doug'\r\n    year: 2001\r\n     day: 'Fri'\r\n5\r\n    name: 'brett'\r\n    year: 2005\r\n     day: 'Mon'\r\n6\r\n    name: 'mike'\r\n    year: 2005\r\n     day: 'Mon'\r\n7\r\n    name: 'jiro'\r\n    year: 2006\r\n     day: 'Mon'\r\n<\/pre><p>Thanks for this entry, Jake. One recommendation I have is to include a couple of examples in the HELP text in the code.<\/p><p><b>Edit (R2017a)<\/b><\/p><p>From R2017a, you can use <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/double.sortrows.html#bt8bz9j-4\"><tt>sortrows<\/tt> with tables<\/a> to accomplish a similar task cleanly and efficiently.<\/p><pre class=\"codeinput\">Atable = struct2table(A);\r\nAtable_sorted = sortrows(Atable,<span class=\"string\">'name'<\/span>)\r\n<\/pre><pre class=\"codeoutput\">Atable_sorted =\r\n  7&times;3 table\r\n      name       year      day  \r\n    _________    ____    _______\r\n    {'brett'}    2005    {'Mon'}\r\n    {'doug' }    2001    {'Fri'}\r\n    {'jiro' }    2006    {'Mon'}\r\n    {'loren'}    1987    {'Fri'}\r\n    {'mike' }    2005    {'Mon'}\r\n    {'seth' }    1998    {'Mon'}\r\n    {'steve'}    1993    {'Wed'}\r\n<\/pre><p><b>Comments<\/b><\/p><p>Give this a try and et us know what you think <a href=\"http:\/\/blogs.mathworks.com\/pick\/?p=2595#respond\">here<\/a> or leave a <a href=\"http:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/28573-nested-sort-of-structure-arrays#comment\">comment<\/a> for Jake.<\/p><script language=\"JavaScript\"> <!-- \r\n    function grabCode_51383107669146d99116b6a2ee25f5f2() {\r\n        \/\/ Remember the title so we can use it in the new page\r\n        title = document.title;\r\n\r\n        \/\/ Break up these strings so that their presence\r\n        \/\/ in the Javascript doesn't mess up the search for\r\n        \/\/ the MATLAB code.\r\n        t1='51383107669146d99116b6a2ee25f5f2 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 51383107669146d99116b6a2ee25f5f2';\r\n    \r\n        b=document.getElementsByTagName('body')[0];\r\n        i1=b.innerHTML.indexOf(t1)+t1.length;\r\n        i2=b.innerHTML.indexOf(t2);\r\n \r\n        code_string = b.innerHTML.substring(i1, i2);\r\n        code_string = code_string.replace(\/REPLACE_WITH_DASH_DASH\/g,'--');\r\n\r\n        \/\/ Use \/x3C\/g instead of the less-than character to avoid errors \r\n        \/\/ in the XML parser.\r\n        \/\/ Use '\\x26#60;' instead of '<' so that the XML parser\r\n        \/\/ doesn't go ahead and substitute the less-than character. \r\n        code_string = code_string.replace(\/\\x3C\/g, '\\x26#60;');\r\n\r\n        copyright = 'Copyright 2020 The MathWorks, Inc.';\r\n\r\n        w = window.open();\r\n        d = w.document;\r\n        d.write('<pre>\\n');\r\n        d.write(code_string);\r\n\r\n        \/\/ Add copyright line at the bottom if specified.\r\n        if (copyright.length > 0) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (copyright.length > 0) {\r\n                d.writeln('% _' + copyright + '_');\r\n            }\r\n        }\r\n\r\n        d.write('<\/pre>\\n');\r\n\r\n        d.title = title + ' (MATLAB code)';\r\n        d.close();\r\n    }   \r\n     --> <\/script><p style=\"text-align: right; font-size: xx-small; font-weight:lighter;   font-style: italic; color: gray\"><br><a href=\"javascript:grabCode_51383107669146d99116b6a2ee25f5f2()\"><span style=\"font-size: x-small;        font-style: italic;\">Get \r\n      the MATLAB code <noscript>(requires JavaScript)<\/noscript><\/span><\/a><br><br>\r\n      Published with MATLAB&reg; R2020b<br><\/p><p class=\"footer\"><br>\r\n      Published with MATLAB&reg; R2020b<br><\/p><\/div><!--\r\n51383107669146d99116b6a2ee25f5f2 ##### SOURCE BEGIN #####\r\n%%\r\n% <http:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/authors\/15007\r\n% Jiro>'s pick this week is\r\n% <http:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/28573-nested-sort-of-structure-arrays\r\n% Nested Struct Sort> by\r\n% <http:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/authors\/106570 Jake\r\n% Hughey>.\r\n%\r\n% MATLAB has a nice function\r\n% <http:\/\/www.mathworks.com\/access\/helpdesk\/help\/techdoc\/ref\/sortrows.html\r\n% |sortrows|> to sort matrices (numeric or cells) based on specific\r\n% column(s). I use it often when I am doing some data management. If you\r\n% have <http:\/\/www.mathworks.com\/products\/statistics\/ Statistics Toolbox>,\r\n% there are corresponding functions for\r\n% <http:\/\/www.mathworks.com\/access\/helpdesk\/help\/toolbox\/stats\/dataset.sortrows.html\r\n% dataset arrays> and\r\n% <\r\n% ordinal arrays>.\r\n%\r\n% Sometimes, I want to do a similar action on structure arrays. I want to\r\n% be able to sort according to specific fields. In order to do that, it\r\n% requires some data manipulations. Let's take a look at an example.\r\n\r\nA = struct(...\r\n    'name', {'mike', 'doug', 'steve', 'loren', 'jiro', 'brett', 'seth'}, ...\r\n    'year', {2005, 2001, 1993, 1987, 2006, 2005, 1998}, ...\r\n    'day', {'Mon', 'Fri', 'Wed', 'Fri', 'Mon', 'Mon', 'Mon'})\r\n\r\nfor id = 1:length(A)\r\n    fprintf('%d\\n',id)\r\n    disp(A(id))\r\nend\r\n\r\n%%\r\n% Let's sort the array by the field \"name\". First you need to convert to a\r\n% cell array:\r\n\r\nAfields = fieldnames(A);\r\nAcell = struct2cell(A);\r\nsz = size(Acell)            % Notice that the this is a 3 dimensional array.\r\n                            % For MxN structure array with P fields, the size\r\n                            % of the converted cell array is PxMxN\r\n\r\n%%\r\n% Once it's a cell array, you can sort using |sortrows|:\r\n\r\n% Convert to a matrix\r\nAcell = reshape(Acell, sz(1), []);      % Px(MxN)\r\n\r\n% Make each field a column\r\nAcell = Acell';                         % (MxN)xP\r\n\r\n% Sort by first field \"name\"\r\nAcell = sortrows(Acell, 1)\r\n\r\n%%\r\n% And convert it back to a structure array:\r\n\r\n% Put back into original cell array format\r\nAcell = reshape(Acell', sz);\r\n\r\n% Convert to Struct\r\nAsorted = cell2struct(Acell, Afields, 1);\r\n\r\nfor id = 1:length(Asorted)\r\n    fprintf('%d\\n',id)\r\n    disp(Asorted(id))\r\nend\r\n\r\n%%\r\n% *Simpler Approach*\r\n%\r\n% Do you want an easier way of doing it? Just use Jake's |nestedSortStruct|:\r\nB = nestedSortStruct(A, 'name');\r\n\r\nisequal(B, Asorted)\r\n\r\n%%\r\n% You can even sort by multiple fields. For example, let's sort by \"year\"\r\n% and then by \"name\":\r\nC = nestedSortStruct(A, {'year', 'name'});\r\n\r\nfor id = 1:length(C)\r\n    fprintf('%d\\n',id)\r\n    disp(C(id))\r\nend\r\n\r\n%%\r\n% Thanks for this entry, Jake. One recommendation I have is to include a\r\n% couple of examples in the HELP text in the code.\r\n%\r\n% *Edit (R2017a)*\r\n%\r\n% From R2017a, you can use\r\n% <https:\/\/www.mathworks.com\/help\/matlab\/ref\/double.sortrows.html#bt8bz9j-4\r\n% |sortrows| with tables> to accomplish a similar task cleanly and\r\n% efficiently.\r\n\r\nAtable = struct2table(A);\r\nAtable_sorted = sortrows(Atable,'name')\r\n\r\n%%\r\n% *Comments*\r\n%\r\n% Give this a try and et us know what you think\r\n% <http:\/\/blogs.mathworks.com\/pick\/?p=2595#respond here> or leave a\r\n% <http:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/28573-nested-sort-of-structure-arrays#comment\r\n% comment> for Jake.\r\n##### SOURCE END ##### 51383107669146d99116b6a2ee25f5f2\r\n-->","protected":false},"excerpt":{"rendered":"<p>\r\n\r\nJiro'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... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/pick\/2010\/09\/17\/sorting-structure-arrays-based-on-fields\/\">read more >><\/a><\/p>","protected":false},"author":35,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[16],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts\/2595"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/users\/35"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/comments?post=2595"}],"version-history":[{"count":2,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts\/2595\/revisions"}],"predecessor-version":[{"id":11787,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts\/2595\/revisions\/11787"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/media?parent=2595"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/categories?post=2595"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/tags?post=2595"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}